← RFC Reference

Understanding Email Bounces

Email Concepts Encyclopedia
ELI5: A bounce is like a “return to sender” stamp on a physical letter. A hard bounce means the address doesn’t exist — it is permanent. A soft bounce means the mailbox is full or the server is busy — it is temporary. The post office sends back a form (DSN) explaining exactly what happened, with a code like “5.1.1” that means “no such mailbox.” Your job is to read these codes, stop sending to dead addresses, and retry the temporary ones.

Hard bounces, soft bounces, DSN format, enhanced status codes — and how to handle them programmatically without destroying your sender reputation.

Two Ways Bounces Happen

Email delivery can fail at two distinct points, and the mechanism differs for each:

Synchronous rejection (during the SMTP session)

The receiving server rejects the message in real time, during the SMTP conversation. You get the error immediately as an SMTP response code:

RCPT TO:<nonexistent@example.com>
550 5.1.1 The email account that you tried to reach does not exist.

This is the cleanest type of bounce. Your sending server knows immediately that delivery failed and can act on it.

Asynchronous bounce (DSN after acceptance)

The receiving server accepts the message (250 OK at DATA), but later discovers it cannot deliver — the mailbox is over quota, content filtering rejected it, or an internal relay failed. The server generates a Delivery Status Notification (DSN) and sends it back to the envelope sender (MAIL FROM address).

This is why the MAIL FROM address matters. It is the address that receives bounce notifications. For transactional email, this is often a dedicated bounce-processing address like bounces+tag@yourdomain.com.

Hard Bounces vs. Soft Bounces

Hard Bounce Soft Bounce
SMTP code 5xx (permanent) 4xx (temporary)
Meaning Delivery will never succeed Delivery may succeed later
Examples User unknown, domain doesn't exist, address rejected by policy Mailbox full, server busy, greylisting, rate limiting
Action Remove from list immediately Retry with backoff; suppress after repeated failures

The distinction is critical. Continuing to send to hard-bounce addresses damages your sender reputation. Mailbox providers track your bounce rate — if it exceeds roughly 2%, your deliverability will suffer across the board.

Enhanced Status Codes

Modern SMTP servers use enhanced status codes (RFC 3463, registry in RFC 5248) that provide much more detail than the basic three-digit code. The format is class.subject.detail:

Subject categories

Subject Category Description
X.0.X Other/undefined Catch-all for uncategorized status
X.1.X Addressing Problems with the mailbox or address
X.2.X Mailbox Mailbox status (full, disabled, etc.)
X.3.X Mail system Destination mail system issues
X.4.X Network/routing Network or routing failures
X.5.X Mail delivery protocol SMTP protocol issues
X.6.X Message content Content or media problems
X.7.X Security/policy Security or policy violations

Status codes you will see most

Code Meaning Action
5.1.0 Other address status Hard bounce — remove
5.1.1 Bad destination mailbox address Hard bounce — the mailbox does not exist. Remove immediately.
5.1.2 Bad destination system address Hard bounce — the domain itself is invalid
5.1.3 Bad destination mailbox address syntax Hard bounce — malformed address
4.2.1 / 5.2.1 Mailbox disabled Account suspended or deactivated
4.2.2 / 5.2.2 Mailbox full Over quota. Temporary if 4xx, permanent if 5xx.
5.2.3 Message too large Reduce message size or attachments
4.4.1 Connection timed out Retry later
4.4.2 Connection dropped Retry later
5.7.1 Delivery not authorized Policy rejection — message or sender is blocked
5.7.26 DMARC failure Fix your authentication records (SPF, DKIM, DMARC)
4.7.1 Greylisting / rate limiting Retry after delay

DSN Format: What a Bounce Message Looks Like

When a bounce is generated asynchronously, it arrives as a structured message defined by RFC 3464, wrapped in RFC 3462's multipart/report MIME type. A DSN has three parts:

Content-Type: multipart/report; report-type=delivery-status;
boundary="boundary42"

--boundary42
Content-Type: text/plain

Your message to bob@example.com could not be delivered.
The recipient's mailbox does not exist.

--boundary42
Content-Type: message/delivery-status

Reporting-MTA: dns; mx1.example.com
Arrival-Date: Tue, 11 Mar 2026 14:00:00 +0000

Final-Recipient: rfc822; bob@example.com
Action: failed
Status: 5.1.1
Diagnostic-Code: smtp; 550 5.1.1 User unknown
Last-Attempt-Date: Tue, 11 Mar 2026 14:00:05 +0000

--boundary42
Content-Type: message/rfc822

[Original message headers included here]

--boundary42--

The three MIME parts:

  1. text/plain — Human-readable explanation
  2. message/delivery-status — Machine-readable structured data with the status code, recipient, and diagnostic info
  3. message/rfc822 — The original message headers (or full message), so you can identify which message bounced

The key fields for programmatic processing:

Handling Bounces Programmatically

Use VERP for reliable identification

VERP (Variable Envelope Return Path) encodes the recipient address into the MAIL FROM, so when a bounce comes back, you can identify exactly which recipient bounced without parsing the DSN body:

MAIL FROM:<bounces+bob=example.com@yourdomain.com>

When bob@example.com bounces, the DSN is delivered to bounces+bob=example.com@yourdomain.com. You parse the local part to extract the original recipient. This works even when the DSN is malformed or non-standard.

Processing logic

A reliable bounce processor follows this logic:

  1. Parse the DSN — Extract the message/delivery-status part. Read the Status: field.
  2. Classify the bounce:
    • Status starts with 5. → Hard bounce. Suppress the address.
    • Status starts with 4. → Soft bounce. Increment a counter.
  3. Apply suppression rules:
    • 1 hard bounce → suppress immediately
    • N soft bounces within a window (e.g., 3 within 7 days) → suppress as hard
  4. Identify via VERP if DSN parsing fails (many servers send non-standard bounces)
  5. Record everything — Log the status code, diagnostic, timestamp, and original message ID for debugging

Watch for false hard bounces

Some servers incorrectly return 5xx for temporary conditions (like rate limiting). If you see 5.7.1 with a message about "too many connections" or "try again later," treat it as a soft bounce despite the 5xx class. Use the diagnostic text as a secondary signal.

Bounce Rate and Reputation

Mailbox providers monitor your bounce rate as a signal of list hygiene:

For transactional email (password resets, receipts), bounce rates should be well under 1%. High bounce rates on transactional mail suggest your application is accepting invalid addresses at signup. Add email validation before ever sending.

What Can Go Wrong

Ignoring bounces entirely

The most common mistake. If you keep sending to addresses that hard-bounce, mailbox providers will throttle and eventually block your sending IP. Your deliverability will degrade for all recipients, not just the invalid ones.

Non-standard bounce formats

Not all MTAs generate RFC-compliant DSNs. Some send plain text bounces with no message/delivery-status part. Others include the status code only in the human-readable text. Your parser needs to handle these gracefully — which is why VERP is so valuable as a fallback identification method.

Backscatter

When a server accepts a message from a spoofed sender and then generates a bounce, that bounce goes to the forged MAIL FROM address. The innocent domain owner receives bounce messages for mail they never sent. This is called backscatter and is a form of abuse. Modern servers should reject during the SMTP session (synchronously) rather than accepting and bouncing later.

Bounce loops

If your bounce-processing address itself bounces (because of a misconfiguration), it can create a loop. SMTP prevents infinite loops by requiring that bounce messages (those with MAIL FROM:<>) are never themselves bounced — they are silently discarded if delivery fails.

Suppression list management

Once you suppress an address, you need a process for re-enabling it. People fix their mailbox (clear quota, re-enable account). A common pattern: allow recipients to re-validate by successfully receiving a confirmation email after a cooling-off period (30-90 days).

Key Takeaways

Further Reading

Related RFCs