emailmarketing.net

Delivery Status Notifications — DSN Format (RFC 3464)

How bounce messages are structured: the multipart/report DSN format, per-message and per-recipient fields (Action, Status, Diagnostic-Code), and how senders should parse them.

Referenceesp-operatorsender

RFC 3464 defines the standard format of the machine-readable bounce message — the Delivery Status Notification (DSN). When a message cannot be delivered (or delivery is delayed, or a requested positive notification fires), the reporting MTA sends a DSN back to the envelope sender. Every automated bounce processor is, at its core, a parser of this format plus heuristics for the non-conforming remainder.

Envelope rules

  • A DSN sent over SMTP MUST use a null return path: MAIL FROM:<>. This prevents mail loops — no DSN is ever generated for a DSN.
  • Corollary for senders: bounces arrive at whatever address you put in MAIL FROM on the original message. Using a per-recipient encoded return path (VERP, e.g. bounces+user=example.com@sender.com) lets you identify the failed recipient even when the DSN body is malformed — and lets a feedback-loop processor reuse the same suppression pipeline.
  • Each sender-specified recipient SHOULD result in at most one "delivered" or "failed" DSN. When a message hits a mailing-list alias, the forwarding MTA SHOULD issue an "expanded" DSN for the original recipient and not propagate the DSN request to the expanded addresses.

Overall structure: multipart/report

A DSN is a MIME message with Content-Type: multipart/report; report-type=delivery-status, containing:

Part Content-Type Purpose
1 text/plain (typically) Human-readable explanation of what happened
2 message/delivery-status Machine-parsable status — the part bounce processors read
3 message/rfc822 or text/rfc822-headers The returned original message (or its headers) — optional

The message/delivery-status part is a set of header-style field groups: one per-message group, then one per-recipient group for each recipient reported, each group separated by a blank line.

Per-message fields

Field Required? Syntax / meaning
Reporting-MTA Required mta-name-type; mta-name — the MTA reporting the result, e.g. dns; mail.example.net
Original-Envelope-Id Optional Transaction ID supplied at submission, for correlating the DSN with the original send
DSN-Gateway Conditional Present only when the DSN was translated from a foreign (non-Internet) reporting system
Received-From-MTA Optional Name of the MTA the message was received from
Arrival-Date Optional RFC 822 date-time the message arrived at the reporting MTA

MTA names are case-sensitive; spelling must be preserved exactly.

Per-recipient fields

Field Required? Syntax / meaning
Final-Recipient Required address-type; generic-address — the recipient address as the reporting MTA saw it
Action Required One of five values, below
Status Required Enhanced status code, DIGIT.1*3DIGIT.1*3DIGIT (e.g. 5.1.1)
Original-Recipient Optional The address as originally specified by the sender (before forwarding/rewriting)
Remote-MTA Optional The next-hop MTA involved in the reported delivery attempt
Diagnostic-Code Optional diagnostic-type; text — the actual transport-level error, e.g. the remote server's full SMTP reply
Last-Attempt-Date Optional RFC 822 date-time of the final delivery attempt
Final-Log-ID Optional Index into the reporting MTA's delivery log
Will-Retry-Until Optional For delayed only — when the MTA will give up

Action values (exactly five, case-insensitive)

Action Meaning Bounce-processor handling
failed Could not be delivered; abandonment is final The bounce. Classify via Status + Diagnostic-Code
delayed Not yet delivered; retries continue (check Will-Retry-Until) Informational; do not suppress — a failed DSN may or may not follow
delivered Successfully delivered to the recipient address Positive DSN (only if requested); not a bounce
relayed Forwarded into an environment that does not accept DSN responsibility Terminal for DSN purposes, but not proof of delivery
expanded Delivered to the sender-specified address, which was a multi-recipient alias/list that re-sent it Non-terminal; only used for multi-recipient aliases

Status vs Diagnostic-Code

  • Status carries the transport-independent enhanced status code — the primary classification key (4.x.x soft, 5.x.x hard).
  • Diagnostic-Code retains the raw transport error; type smtp means the text is the remote server's SMTP reply. The RFC notes it is "somewhat redundant" with Status but is provided to retain the original information. When Remote-MTA is present, the diagnostic came from that MTA; otherwise from the reporting MTA. In practice the diagnostic text often carries provider-specific detail (blocklist names, policy URLs, "user unknown") that the numeric Status lacks — parse both.

Type conventions

  • address-type, mta-name-type, diagnostic-type values are case-insensitive atoms: standard values are rfc822 (addresses), dns (MTA names), smtp (diagnostics); unknown when the type can't be determined; X- prefix for experimental types; new types are IANA-registered.
  • The content after the type may be case-sensitive (mailbox local parts) and must be preserved exactly.

Example (from the RFC)

Reporting-MTA: dns; cs.utk.edu

Original-Recipient: rfc822;louisl@larry.slip.umd.edu
Final-Recipient: rfc822;louisl@larry.slip.umd.edu
Action: failed
Status: 4.0.0
Diagnostic-Code: smtp; 426 connection timed out
Last-Attempt-Date: Thu, 7 Jul 1994 17:15:49 -0400

Parsing guidance for senders

  1. Identify the recipient: prefer Original-Recipient, fall back to Final-Recipient; strip the rfc822; type prefix. If the body is unparsable, fall back to the VERP-encoded return path.
  2. Gate on Action: only failed drives suppression. Ignore delayed for list hygiene (log it for delivery monitoring); treat delivered/relayed/expanded as non-bounces.
  3. Classify on Status: 5.x.x → hard-bounce logic, 4.x.x → soft-bounce counters. Use the detail-code table to separate bad-address codes (suppress) from policy/reputation codes (investigate — a wave of 5.7.1 is a sender problem, not a list problem).
  4. Refine on Diagnostic-Code: regex/keyword rules over the raw SMTP text catch provider-specific conditions the numeric code hides (named blocklists, "spam content", rate-limit notices).
  5. Expect multiple recipient groups per DSN — one bounce message can report several recipients; process each group independently.
  6. Expect non-conformance: plenty of real-world bounces are free-form text with no message/delivery-status part at all. RFC 3464 parsing is the fast path; keep a heuristic fallback and VERP as the safety net.
  7. Never auto-reply to a DSN and never send bounces of your own with a non-null return path — the MAIL FROM:<> rule is what keeps the ecosystem loop-free.
#bounce-handling#dsn#bounces#rfc3464#multipart-report#ndr#verp