# Handle bounces and protect your sending

Receiving mail servers judge a sender by how much of their mail is unwanted. Lessly Mail keeps two records that protect you from that judgement: a **suppression list** of addresses it will not send to, and a **reputation** report showing how your recent sending looks from the outside. Both are maintained for you — what you do is read them, and occasionally correct them.

## Check whether an address is suppressed

This is the question you actually have when a customer says their reset link never arrived. An agent calls [`mail_suppression_list`](/reference/mcp-tools/mail_suppression_list); over REST it is `GET /mail/suppressions` on the [Mail API](/reference/openapi/mail).

The list is read a page at a time — between 1 and 100 entries, 50 by default — with a cursor for the next page. You can narrow it to a single reason, or to addresses containing a given substring, which is the fastest way to answer "is this customer suppressed, and why". Each entry carries its address, its reason, its note, the moment it was added, and, when the entry came from a bounce or a complaint, a reference to the event that caused it.

## Why addresses land on the list

The suppression list is a set of recipient addresses, held per product. Every send is checked against it, whichever way the message was created.

| Reason | How the address got there |
|---|---|
| `hard_bounce` | A message to it was permanently rejected |
| `complaint` | The recipient marked a message as spam |
| `unsubscribe` | The recipient used an unsubscribe link |
| `manual` | You added it yourself |

The first three are added for you, as the outcome arrives; you never have to prune your own lists after a bounce.

> Addresses are stored trimmed and lower-cased, and matched that way. No other canonicalisation is applied: `user+tag@example.com` and `user@example.com` are two different addresses as far as the list is concerned.

## Add or remove an address yourself

1. **Add one.** You can suppress an address yourself — someone asked you by email to stop, or you know a mailbox is dead. An agent calls [`mail_suppression_add`](/reference/mcp-tools/mail_suppression_add); over REST, `POST /mail/suppressions`. It takes the address and, optionally, a free text note of up to 1000 characters for whoever reads the list later. The reason is always recorded as `manual`.

   Adding is idempotent, and the first entry wins: adding an address that is already suppressed leaves the existing entry, and its original reason, untouched.

2. **Remove one.** An agent calls [`mail_suppression_remove`](/reference/mcp-tools/mail_suppression_remove); over REST, `DELETE /mail/suppressions/:address`. It tells you whether an entry was actually there, so removing an address that was never suppressed is not an error.

> Removal is the only way an address leaves the list — nothing expires on its own. Remove an entry only when you know the address is deliverable again; re-sending to an address that hard-bounced will bounce again and suppress it a second time.

## What happens when you send to a suppressed address

Nothing is rejected outright. Suppression is applied per recipient, across `to`, `cc` and `bcc`:

- Suppressed recipients are dropped from the message before it goes anywhere.
- Every dropped recipient produces an `email.suppressed` event, so the skip is visible in the message's history and on your webhooks.
- If some recipients survive, the message is queued and sent to those only.
- If every recipient was dropped, the message is never handed over at all. It is created with the status `suppressed` and ends there.

The check runs twice: when the message is accepted, and again immediately before it goes out. That second check is what makes a scheduled message safe — an address suppressed during the wait is still dropped.

## Bounces and complaints

When the receiving side reports back, the outcome is recorded as an event on the message and, where it is decisive, on the message's status.

| Outcome | What it is | Effect |
|---|---|---|
| Hard bounce | A permanent rejection — the mailbox does not exist, the domain does not accept mail | Status becomes `bounced`; the recipient is added to the suppression list |
| Soft bounce | Temporary — a full mailbox, a server that was busy | Recorded as an event with bounce kind `soft`, or `undetermined` when the receiving server was not specific. The status does not change and no address is suppressed |
| Complaint | The recipient pressing "this is spam" | Status becomes `complained`; the address is suppressed |

Every one of these is delivered to your webhooks as it happens, and appears in the message's own history. See [receive delivery events](/ship/mail/webhooks) for the payload and [send a message](/ship/mail/sending) for reading a message back.

## Read your reputation

An agent calls [`mail_reputation_get`](/reference/mcp-tools/mail_reputation_get); over REST, `GET /mail/reputation`. Your sender reputation is a rolling measurement of how badly your recent sending went, computed over the last **7 days**.

| Field | Meaning |
|---|---|
| `volume` | Recipients of messages handed over in the window |
| `hard_bounces`, `complaints` | Counts of each in the window |
| `hard_bounce_rate`, `complaint_rate` | Those counts over `volume`, as ratios between 0 and 1 |
| `thresholds` | The limits the two rates are measured against, and the minimum volume |
| `gated` | Whether sending is currently throttled |
| `tripped_metric` | `hard_bounce`, `complaint`, or `null` when nothing tripped |
| `window_days` | The length of the window the numbers cover |

Two limits apply: a hard-bounce rate above **4%** and a complaint rate above **0.08%**. Neither is considered until the window holds at least **1000** recipients, so a handful of bounces on your first day of sending cannot throttle you. Above that volume, either rate crossing its limit sets `gated` and names itself in `tripped_metric`.

### What happens while you are gated

Sending is paused for the whole product. New messages are rejected with a `reputation_throttled` error and a message naming the rate, the limit and the window. Messages already queued or scheduled are not sent either — they are checked again when they come due and end with the status `blocked`.

Nothing has to be reset by hand. The window keeps rolling, and as the offending rate falls back under its limit sending resumes on its own. The way out is to stop sending to addresses that bounce and to people who did not ask to hear from you; the suppression list does the first of those for you.

> Because the report is recomputed at most once a minute, it can lag your very latest sends by up to that long.

## Read your statistics

An agent calls [`mail_stats_get`](/reference/mcp-tools/mail_stats_get); over REST, `GET /mail/stats`. The statistics view aggregates a whole product over a period of **7, 30 or 90 days** — 30 by default. It answers "how much did we send, and how much of it landed".

| Group | What it holds |
|---|---|
| Totals | `sent`, `delivered`, `bounced` and `complained` for the period. `sent` counts recipients of messages that were handed over, not messages, so a single message to four people counts as four. |
| Deltas | The change in each total against the immediately preceding period of the same length, as a percentage. A delta is `null` when the previous period was zero, because there is no meaningful change from nothing. |
| Volume | One bucket per UTC day across the period, each with its `sent`, `delivered` and `bounced` counts. Days with no activity are present with zeroes, so the series is always the full length of the period. |
| Deliverability | `delivered`, `bounced` and `complained` as percentages of `sent`, rounded to one decimal place, and zero when nothing was sent. |

Delivered, bounced and complained counts are the events that arrived in the window. Because a message sent late in a window can be delivered after it closes, the delivered percentage of a very recent window reads low and settles as the outcomes come in.

## Next steps

- [Receive delivery events](/ship/mail/webhooks): be told about each bounce and complaint as it happens.
- [Send a message](/ship/mail/sending): what `suppressed` and `blocked` mean on a message you sent.
- [Set up a sending domain](/ship/mail/domains): the DKIM and DMARC records receiving servers judge you by.
- [How system email works](/ship/mail): where reputation sits in the wider flow.
