Home
Email Deliverability

Bounce Handling Guide for Reliable Email Workflows

Bounce events passing through classification, suppression, and monitoring gates

A useful bounce handling guide starts with one rule: do not treat every failed delivery as a dead address. Capture the event, identify whether delivery is delayed or terminal, read the machine-readable status, and make a recipient-level decision before the next send.

That distinction protects two things at once. You avoid sending repeatedly to invalid recipients, and you avoid suppressing valid recipients because of a temporary server or policy problem.

Hard bounce vs soft bounce: read the status before acting

Email systems commonly describe permanent failures as hard bounces and temporary failures as soft bounces. The formal signal is the enhanced status code defined by RFC 3463. Its first number gives the broad class:

ClassMeaningApplication response
2.x.xSuccessRecord the accepted outcome.
4.x.xPersistent transient failureObserve the provider's retry state and wait for a terminal result.
5.x.xPermanent failure for the message as sentInspect the subject and detail codes before deciding whether to suppress the recipient.

A 5.x.x result does not always mean the mailbox is missing. 5.1.1 describes a bad destination mailbox address, while other permanent codes can describe message size, content, authentication, routing, or policy. Permanent message failure and permanent recipient suppression are separate decisions.

The detail matters for temporary failures too. RFC 3463 describes X.2.2 as a full mailbox and classifies it as persistent transient. A delayed delivery event should remain pending while the sending provider is still retrying it.

Build a four-stage bounce handling pipeline

Keep the flow small enough to audit:

  1. Capture the event. Accept the provider event, verify its authenticity, and store the raw payload before applying business rules.
  1. Normalise the result. Map the provider category, SMTP reply, enhanced status code, recipient, message identifier, and event time into your own stable fields.
  1. Decide the action. Mark the outcome as delivered, delayed, recipient-invalid, message-invalid, policy-blocked, complained, or undetermined.
  1. Enforce the decision. Update recipient suppression, stop unsafe queued sends, preserve the evidence, and notify the owning workflow when intervention is needed.

Bounce events moving through capture, normalisation, decision, and enforcement gates

Each stage should be idempotent. The same event may arrive again, so a stable event identifier must resolve to the same stored result without incrementing counters twice.

Parse DSNs as structured data

A Delivery Status Notification, or DSN, is a MIME report intended for machine processing. RFC 3464 defines the message/delivery-status part and its per-recipient fields.

Read fields such as Final-Recipient, Action, Status, and Diagnostic-Code from that structured part. Keep the human-readable explanation for support work, but do not make it the primary input to an automated classifier.

The Action field also prevents premature decisions. A delayed action means the reporting system has not delivered the message yet but plans to continue trying. A failed action means it has abandoned delivery for that recipient.

Provider webhooks can present the same outcome in a cleaner JSON form. Preserve both the normalised decision and the original provider values so a later rule change can be audited against the evidence that arrived.

Avoid duplicate retries

Separate delivery retries from application retries.

When a sending provider reports a delayed delivery and says it is still retrying, your application should not submit a second logical email. That can create duplicate delivery if the original attempt later succeeds.

Use one logical message identifier and keep its state pending until a delivered or terminal event arrives. If a network request failed before you received an API response, retry with the same idempotency key where the sending API supports it.

Do not apply one universal schedule to every provider and message stream. Provider queue policy, message expiry, recipient error detail, and the purpose of the email all affect the safe response. Record the provider's retry deadline when one is supplied, then expire your pending state after the provider reaches a terminal outcome.

Design recipient suppression for decisions and audits

A suppression record needs enough context to block the right send without hiding why it happened.

FieldWhy keep it
Normalised recipientProvides the pre-send lookup key.
ScopeSeparates team, tenant, domain, or stream policy.
Decision and reasonDistinguishes an invalid recipient from content or policy failure.
Enhanced and provider codesPreserves the evidence used by the classifier.
Source event and message IDsSupports deduplication and reconciliation.
First and latest event timesShows whether a pattern is new or persistent.
ExpiryAllows a reviewed temporary hold without weakening permanent suppression.

Check suppression before accepting a logical send into the dispatch path. Updating a list after another message has already left the queue is too late.

Provider-managed suppression is useful, but it does not replace your application record. For example, Amazon SES documents provider-side suppression behaviour and permanent suppression bounce categories. Your application still needs the recipient, tenant scope, business reason, and source event that explain its own decision.

Monitor the rate and the reason

A bounce rate without a denominator or time window is hard to use. Track outcomes by provider, sending account, domain, stream, and recipient cohort. Keep permanent bounces, transient delays, policy blocks, complaints, and pre-send rejections separate.

Compare a short window with a longer baseline. A sudden cluster can point to a bad recipient import or provider incident. A steady rise may indicate list ageing, broken authentication, or a sending-policy change.

Pause the affected stream when the evidence shows ongoing harm. Verify that suppression checks are actually blocking sends, inspect the recent recipient source, and resume only after the cause is understood.

Use Sendmux bounce events without exposing queue internals

Sendmux signed webhooks include message.bounced and message.delivery_delayed events. The delayed event means delivery is still being retried. Each delivery carries an event ID that your endpoint can use for deduplication.

Verify the webhook signature before processing the body. Route on the public event type, store the stable event ID, and reconcile the result with delivery logs.

The public event payload can include a permanent, transient, or undetermined bounce category plus a more specific subtype when available. Your application owns the final suppression rule because it knows the recipient scope and business context.

Sendmux also shows bounce and complaint signals across recent windows in its deliverability view. Use those aggregates to find the affected stream, then use event and message-level evidence for the actual decision.

Sources

Frequently Asked Questions

What's the difference between a hard bounce and a soft bounce?

A hard bounce usually describes a permanent delivery failure, represented by a 5.x.x enhanced status class. A soft bounce usually describes a persistent transient failure in the 4.x.x class. Inspect the detail code before suppressing a recipient because not every permanent message failure means the address is invalid.

How long should you retry a soft bounce before giving up?

There is no universal application retry schedule. If the sending provider reports that delivery is delayed and still being retried, keep the logical message pending instead of submitting a duplicate. Use the provider's terminal event or retry deadline, when supplied, to close the attempt.

Should you rely on your provider's hard or soft bounce label?

Use the provider label as evidence, then retain the enhanced status code, subtype, diagnostic, and original event. Your application should apply a stable recipient-suppression rule that reflects the error detail, tenant scope, and message context.

What fields belong in a bounce suppression table?

Store the normalised recipient, suppression scope, decision, reason, enhanced and provider codes, source event ID, message ID, first and latest event times, and an optional expiry. Those fields support pre-send blocking, deduplication, review, and audit.

Can Sendmux help process bounce events in real time?

Sendmux provides signed webhooks for message.bounced and message.delivery_delayed events, stable event identifiers for deduplication, delivery logs, and deliverability views. Your application remains responsible for its recipient-suppression and workflow decisions.