> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Troubleshooting: email bounces and spam complaints

> Decode the DSN codes and SMTP replies behind a bounced email — hard vs soft vs spam-trap vs complaint — and turn each into a fix: suppress, retry, tighten list hygiene, or repair SPF/DKIM/DMARC alignment.

# Troubleshooting: email bounces and spam complaints

`bounced` is the email channel's terminal failure status — a receiving
mail server returned the message instead of accepting it. Because email
accepts a message and then bounces it later, the bounce arrives on the
same asynchronous webhook path as delivery. This page decodes the DSN
codes and SMTP replies the provider reports, maps each failure family to
the fix, and shows how to read the sender-reputation summary before you
escalate.

If the message was never accepted at all (`failed`, `rejected` on send),
work the channel-agnostic
[message failure page](/troubleshooting/message-undelivered-failed)
first — this page covers only recipient-side rejects after the provider
accepted the send.

## Where you see a bounce

Three surfaces carry the same outcome:

* **Delivery Log** — open the row. A recipient-side bounce resolves to
  the terminal status `bounced` — the email-only terminal status that
  lives in the platform's terminal-failure set alongside `failed`,
  `undelivered`, and `expired` (see the
  [message status lifecycle reference](/api-reference/messages-status-lifecycle)).
  The **Provider Reference** and the failure detail the provider
  returned travel with the row.
* **Webhook** — email delivery outcomes arrive on the channel-agnostic
  `message` events, not email-specific ones. A hard bounce, a soft
  bounce, and a spam complaint all fire `message.failed` with
  `channel: "email"` and the originating `message_id` (see the
  [email channel guide](/channels/email#webhook-events)). Branch on the
  payload's failure detail, not the event type.
* **Deliverability dashboard / API** — the tenant-level summary
  endpoint `GET /api/v1/email/suppressions/reputation` returns the
  aggregate sent / delivered / bounced / complaint counts and rates,
  the health tier and score, and the current suppression-list size over
  a lookback window (see the
  [email endpoints reference](/api-reference/endpoints/email)). Compare
  a single bounce against this baseline before treating it as a trend.

## Hard vs soft vs complaint vs spam-trap

The provider reports a DSN (Delivery Status Notification) code and the
SMTP reply from the rejecting server. Classify it before you act:

| Family                | What the code says                                                         | What it means                                                                                                                                                                             |
| --------------------- | -------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Hard bounce           | `5.1.1` (invalid mailbox), any `5.x.x`                                     | The address does not exist or the domain/ recipient server rejects permanently. Retrying the same address will fail again — remove it.                                                    |
| Soft bounce           | `4.x.x` (mailbox full, temporarily deferred, greylisted)                   | The recipient server throttled or deferred this attempt. Within the provider's retry window the send can still succeed; a persistent `4.x.x` across retries degrades into a hard failure. |
| Spam complaint        | Recipient clicked "report spam"                                            | The recipient told their provider your message is unwanted. The complaint counts against your sender reputation even when the message technically delivered.                              |
| Spam trap / blocklist | The deliverability-surface complaint bucket the reputation endpoint groups | An address that exists only to catch senders who bought lists or never re-validate. A few trap hits can pull the whole sender's health tier down.                                         |

Read the provider's raw reply on the Delivery Log row — `5.1.1` (user
unknown) and `5.2.2` (mailbox full) look identical from the `bounced`
status alone, and the fix differs.

## Cause → fix

| Signal                     | Fix                                                                                                                                                                                                                                                                                                       |
| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Hard bounce (`5.x.x`)      | Remove the address and let the suppression list hold it. A complaint-driven suppression entry stops future sends to that address automatically (see [opt-out suppression](/compliance/opt-out-suppression)); purging invalid addresses before they re-bounce is cheaper than rebuilding reputation after. |
| Soft bounce (`4.x.x`)      | Retry within the provider's retry window, and watch the aggregate soft-bounce rate on the reputation endpoint. A high soft-bounce share means a destination ISP is throttling you — treat it as early signal, not noise.                                                                                  |
| Spam complaint             | Review signup/list hygiene: confirm consent was collected, the opt-out flow is one click, and the sender identity is clear. Each complaint suppresses the recipient and drags the complaint-rate bucket the reputation endpoint reports.                                                                  |
| Spam trap                  | Audit the import source. Trap contamination means addresses came from a purchased or scraped list, or an ancient un-validated import — remove list-purchase sources and re-validate before the next send.                                                                                                 |
| Delivered to spam folder   | Check SPF/DKIM/DMARC alignment on the sending domain and run the deliverability-score lint (spam-trigger keywords, shortened links) before re-sending. "Delivered" in the log with no engagement is a placement problem, not an acceptance problem.                                                       |
| Warmup held at a daily cap | Working as designed — the daily cap is a ramp, not a fault. Check today's recommended cap and remaining headroom with `GET /api/v1/email/warmup-status`; the day-by-day ramp is described in the [warm-up FAQ entry](/reference/faq#what-does-the-email-ip-warmup-plan-do-automatically).                 |

<Tip>
  Lifetime reputation is the score that decides which of these levers
  exists at all. Keep the complaint rate near zero and prune hard
  bounces after the first return — the reputation endpoint's health tier
  and score reflect both.
</Tip>

## Reading the deliverability surface

`GET /api/v1/email/suppressions/reputation` summarises a lookback window
into the numbers to report and trend:

* **sent / delivered / bounced / complaint counts and rates** — the raw
  numerator and denominator for each outcome family so a spike in one
  bucket does not hide in a blended rate.
* **health tier and score** — an ordinal-priority view of how the
  provider-side reputation stack currently scores the sender.
* **suppression-list size** — how many addresses the suppression list
  is actively holding out of future sends right now.
* **shared-IP disclosure** — whether the sender shares sending IP with
  other tenants, which affects how much of your own bounce/complaint
  budget a given number can consume before the pool-averaged health is
  diluted.

Requires an owner or admin role. Full request/response shape is in the
[email endpoints reference](/api-reference/endpoints/email).

## When to escalate

Escalate when the bounce family is genuinely ambiguous or the numbers
are off in a direction you cannot correct from your own list source:

* All destinations return the same family at the same time (points at
  the sending side, not one list).
* The reputation endpoint shows a complaint rate hard-correlated with a
  specific campaign or template.
* SPF/DKIM/DMARC align and content passes the deliverability-score lint,
  yet bulk traffic still lands in spam.

Include these so support traces the row without a back-and-forth:

* Your **tenant ID** (Settings → Organization in the dashboard; also
  returned as `organizationId` by `GET /api/v1/me`).
* One **message ID** of a bouncing row (`msg_…`).
* The **bounce code / SMTP reply** as the provider returned it (read
  from the Delivery Log row's failure detail).
* Your **complaint rate** over the lookback window, from the
  reputation endpoint.

## See also

* [Email channel guide](/channels/email) — webhook events and the
  `message.failed` wire contract
* [Opt-Out & Suppression](/compliance/opt-out-suppression) — how
  suppression list entries stop future sends
* [Message status lifecycle](/api-reference/messages-status-lifecycle) —
  where `bounced` lives and the full transition table
* [Delivery lifecycle](/concepts/delivery-lifecycle) — the concept-level
  state machine behind Delivery Log rows
* [Troubleshooting index](/reference/troubleshooting) — the queue-side
  and pre-submit checks
* [Email endpoints reference](/api-reference/endpoints/email) — the
  sender-reputation and warmup endpoint shapes
