Microsoft NDR, spamtrap reports en bounce-cleanup workflow

Datum: 2026-06-23

Project: impex + Email-marketing-platforms

Samenvatting

Microsoft/Office 365 kan een mail eerst met SMTP 250 accepteren en later alsnog een non-delivery report terugsturen. Daardoor ziet Postfix lokaal status=sent, terwijl de mailbox later via NDR meldt dat de recipient niet bestaat.

status=sent
dsn=2.6.0
250 2.6.0 ... Queued mail for delivery
Your message to peter.dufaux@domain.be couldn't be delivered.
peter.dufaux wasn't found at domain.be.

550 5.1.10 RESOLVER.ADR.RecipientNotFound
Postfix sent betekent alleen dat de ontvangende edge server de mail heeft aangenomen. Bij Microsoft kan daarna alsnog een harde bounce terugkomen via mailbox/Takeout.

Waarom dit belangrijk is

Microsoft kan oude of verwijderde mailboxen als reputatierisico zien. Als er veel naar zulke adressen wordt gestuurd, kan dat in Microsoft reports verschijnen als trap hits of abuse-notificaties richting provider/IP abuse teams. Daarom moeten zowel Postfix logs als Undeliverable mailboxen worden verwerkt.

Beleidsregels

Signaal Voorbeeld Status Bounce type Actie
User unknown wasn't found at, RecipientNotFound bounced hard Uitschakelen
Mailbox full/quota mailbox full, quota exceeded bounced hard Uitschakelen volgens huidig beleid
Hard domain not found host not found, no such domain bounced hard Uitschakelen
Policy/spam block blocked due to policy, low reputation blocked Niet behandelen als kapotte mailbox
DNS technical timeout/refused/message expired deferred soft Niet automatisch hard uitschrijven

Impex: mailbox/Takeout route

Analyseer eerst zonder databasewijzigingen:

python3 manage.py investigate_takeout_undeliverable \
  --mbox /pad/naar/recente/Undeliverable.mbox \
  --subject-contains "Undeliverable:" \
  --write-csv /tmp/recent-undeliverable-investigation.csv \
  --progress-every 50000

Specifiek Office 365 wasn't found at onderzoeken:

python3 manage.py investigate_takeout_undeliverable \
  --mbox /pad/naar/recente/Undeliverable.mbox \
  --subject-contains "Undeliverable:" \
  --body-contains "wasn't found at" \
  --write-csv /tmp/recent-wasnt-found-investigation.csv \
  --progress-every 50000

Report-only databasecheck:

python3 manage.py process_undeliverable_investigation_csv \
  --csv /tmp/recent-undeliverable-investigation.csv \
  --check-db \
  --progress-every 10000

Commit:

python3 manage.py process_undeliverable_investigation_csv \
  --csv /tmp/recent-undeliverable-investigation.csv \
  --commit \
  --progress-every 10000
Office 365 NDR's niet verwerken met --kind unsubscribe. Een NDR is geen menselijke unsubscribe, maar een bounce.

Email-marketing-platforms: Postfix-log route

Op de verzendserver:

cd /pad/naar/Email-marketing-platforms

python manage.py parse_maillogs --mx
python manage.py classify_bounces

python manage.py notify_bounced_contacts \
  --url "$CONTACT_STATUS_UPDATE_URL" \
  --key "$CONTACT_PROVIDER_UPDATE_KEY" \
  --status bounced \
  --bounce-type hard \
  --limit 1000

Deze route verwerkt directe SMTP bounces uit /var/log/mail.log en geroteerde logs. Ze dekt niet alle Microsoft NDR's die pas na 250 Queued mail for delivery terugkomen.

Impex status API

curl -X POST 'https://CONTACT-SERVER/contact/api/email-status/' \
  -H "X-Contact-Provider-Key: $CONTACT_PROVIDER_UPDATE_KEY" \
  -d 'email=peter.dufaux@monard-dhulst.be' \
  -d 'status=bounced' \
  -d 'bounce_type=hard' \
  -d 'status_code=550 5.1.10' \
  -d 'status_message=RESOLVER.ADR.RecipientNotFound; Recipient not found by SMTP address lookup' \
  -d 'provider=business_microsoft' \
  -d 'provider_source=manual_ndr_test'

Dagelijkse werkwijze

  1. Verwerk Postfix logs in Email-marketing-platforms.
  2. Notify hard bounces naar impex.
  3. Exporteer recente Undeliverable mbox uit mailbox/Takeout.
  4. Analyseer die mbox naar CSV.
  5. Check de CSV tegen de database.
  6. Commit hard bounce categorieën.
  7. Bouw Cyclus opnieuw op zonder uitgesloten bronnen.

Queue opnieuw opbouwen

./resetmailing.bash

Equivalent:

python3 manage.py resetcyclus
python3 manage.py addemailsincyclus \
  --exclude-source-names 'FacebookAdsJsonCSV,UnsubscribeTakeOutSpamBlocked,Test,MailTester'

Kernconclusie

De correcte Microsoft-werkwijze is:

Postfix logs verwerken
+ Microsoft/Office 365 Undeliverable mailbox verwerken
+ Contact.for_mailing uitschakelen voor user_unknown/mailbox_full/hard-domain
+ queue opnieuw bouwen zonder uitgesloten bronnen

Alleen zo verdwijnen oude mailboxen snel genoeg uit de actieve queue en dalen Microsoft spamtrap/abuse-signalen.

Comments