All articlesDeliverability

Email Bounce Handling: Hard vs Soft Bounces and How to Process Them

How bounces work, the difference between hard and soft bounces, how to parse DSN messages, build a suppression list, and keep bounce rates under control.

The SMTPTester Team January 6, 2026 15 min read

What a bounce actually is

A bounce is a delivery failure notification. Something in the chain between your application and the recipient's mailbox refused the message, and a report came back explaining why.

Bounces happen at two distinct moments, and confusing them makes debugging much harder.

A synchronous bounce happens during the SMTP session itself. The receiving server returns a 5xx at RCPT TO or after DATA, and your client sees the rejection immediately. These are the cleanest to handle because you have the error in hand at send time.

An asynchronous bounce happens after the receiving server has already accepted the message with a 250. It later discovers it cannot deliver — the mailbox is full, the account was disabled, an internal filter rejected it — and generates a Delivery Status Notification (DSN) sent back to your envelope sender address, often minutes or hours later.

Most large providers accept first and bounce later, so if you only handle synchronous failures you are seeing a fraction of the picture.

Hard bounces versus soft bounces

Hard bounces are permanent. The address will never work. Common causes:

  • The mailbox does not exist (typo, employee left, domain migrated).
  • The domain does not exist or has no MX record.
  • The recipient server permanently blocked you.
  • The address is syntactically invalid.

Soft bounces are temporary. The address is valid but delivery failed right now:

  • Mailbox over quota.
  • Receiving server down or overloaded.
  • Message too large for the recipient's limit.
  • Greylisting on first contact.
  • Temporary rate limiting.

The operational rule is simple and non-negotiable: suppress hard bounces immediately and permanently. Retry soft bounces, then suppress after repeated failures.

Continuing to mail a hard-bounced address is one of the fastest ways to destroy sender reputation. Mailbox providers read it as a sign that you do not maintain your list, which correlates strongly with spam.

Reading a DSN

A bounce message is a structured MIME document, not just prose. It contains a message/delivery-status part with machine-readable fields:

Reporting-MTA: dns; mail.example.com
Final-Recipient: rfc822; nonexistent@example.org
Action: failed
Status: 5.1.1
Diagnostic-Code: smtp; 550 5.1.1 User unknown

The fields you care about:

  • Final-Recipient — the address that failed. Use this, not the To header, which may list several recipients.
  • Actionfailed, delayed, or delivered.
  • Status — the enhanced status code. The first digit tells you hard (5) or soft (4).
  • Diagnostic-Code — the raw SMTP reply from the remote server, which usually contains the real explanation.

Parse the Status field first. It is standardised and reliable. Fall back to pattern-matching the Diagnostic-Code only when Status is missing, which happens with older or non-compliant servers.

Status codes to classify against

Hard (suppress immediately):

CodeMeaning
5.1.1Bad destination mailbox address
5.1.2Bad destination system — domain does not exist
5.1.3Bad destination mailbox address syntax
5.1.6Mailbox has moved
5.2.1Mailbox disabled
5.4.4Unable to route
5.7.1Delivery not authorised — often a block

Soft (retry):

CodeMeaning
4.2.2Mailbox full
4.3.1Insufficient system storage
4.4.1No answer from host
4.4.2Connection dropped
4.7.1Delivery not authorised, temporarily

5.2.2 (mailbox full) is a special case. Technically permanent, but in practice the mailbox may be cleared. Treat it as soft, retry for a few days, and suppress if it never clears.

Building a bounce-handling pipeline

A production system needs five components.

1. A dedicated return path. Set the envelope sender (Return-Path) to a dedicated address on a subdomain you control, such as bounces@mail.yourdomain.com. This is where DSNs arrive. It also fixes SPF alignment for DMARC.

2. Webhook ingestion. If you use a transactional provider, consume its bounce webhooks rather than parsing mail yourself. Providers do the classification for you and deliver structured JSON. Verify the webhook signature, and make the handler idempotent — providers retry, and you will receive duplicates.

3. Classification. Map each event to hard, soft, or complaint. Store the raw diagnostic text alongside your classification so you can audit and correct the rules later.

4. A suppression list. A single table of addresses that must never be mailed again, checked before every send, at the transport layer rather than in each application feature. Columns: address, reason, source, timestamp. Never delete rows — a re-subscription should override with an explicit record, not by dropping the suppression.

5. Retry policy for soft bounces.

attempt 1  ->  after 15 minutes
attempt 2  ->  after 1 hour
attempt 3  ->  after 4 hours
attempt 4  ->  after 12 hours
attempt 5  ->  after 24 hours
still failing after 72 hours -> treat as hard, suppress

Add jitter so parallel workers do not retry in lockstep.

Handling complaints

A complaint — a recipient clicking "report spam" — is more damaging than a bounce. Providers report complaints through feedback loops, and the transactional providers surface them as webhook events.

Rules for complaints:

  • Suppress immediately and permanently. Never mail a complainer again, even for transactional messages if you can avoid it.
  • Investigate the source. A spike in complaints from one campaign or one signup source usually points at a list-quality problem.
  • Keep the rate below 0.1 percent. Gmail's stated enforcement threshold is 0.3 percent, but reputation damage begins well before that.

Note that Gmail does not provide a per-message feedback loop. You see aggregate spam rates in Google Postmaster Tools instead, which is why enrolling in Postmaster Tools is not optional.

Preventing bounces in the first place

Handling bounces is damage control. Preventing them is cheaper.

  • Validate at signup. Syntax check, MX lookup, and disposable-domain detection catch most typos before they enter the list.
  • Use double opt-in. A confirmation email proves the address exists and that a human wanted it.
  • Add a typo-correction hint at signup for common domain mistakes like gmial.com or hotmial.com.
  • Never buy lists. Purchased data has high bounce rates and contains spam traps.
  • Re-verify old lists. Addresses decay at roughly 2 percent per month through job changes and abandonment. A list untouched for two years is largely dead.
  • Sunset inactive subscribers after 6–12 months of no engagement, following one re-engagement attempt.

Rates to watch

MetricHealthyWarningCritical
Hard bounce rateunder 2%2–5%above 5%
Soft bounce rateunder 5%5–10%above 10%
Complaint rateunder 0.1%0.1–0.3%above 0.3%
Unsubscribe rateunder 0.5%0.5–1%above 1%

Above 5 percent hard bounces, most providers begin throttling. Above 10 percent, expect outright blocking.

Diagnosing a sudden bounce spike

  1. Is it one recipient domain or all of them? One domain means a block or a policy change at that provider. All domains means an authentication or infrastructure problem on your side.
  2. Read the diagnostic codes. They usually name the cause, often with a documentation URL.
  3. Check the enhanced status class. A wave of 5.1.1 means list quality. A wave of 5.7.1 means blocking.
  4. Check for a list import. New bounces almost always trace to newly added addresses.
  5. Verify authentication. An expired DKIM key or a broken SPF record produces immediate widespread rejection.
  6. Check blocklists for your domain and sending IPs.
  7. Pause the affected stream while you fix the cause. Continuing to send into a bounce spike compounds the reputation damage.

Retention and privacy

Bounce data contains personal information. Keep the suppression list — you are legally required to honour unsubscribes and practically required to avoid dead addresses — but purge detailed diagnostic logs on a schedule, typically 90 days. Document the retention policy alongside your other data-protection records.

Test the transport before you blame the list

A surprising number of "bounce spikes" turn out to be a broken relay: an expired credential, a certificate that lapsed, a firewall rule added during a migration. Before you start pruning addresses, confirm that your SMTP server still accepts your connection, negotiates TLS, and authenticates correctly. SMTPTester answers all three in a single check, and ruling out the transport layer first will save you from deleting a perfectly good list.

Test your SMTP server now

Apply what you just learned. Free, no signup, results in seconds.

Open the tool →

Continue reading