# Suppressions

Addresses a stream no longer sends to, why they are there, and how to lift one.

Each [stream](https://sendora.se/docs/streams) of a server keeps its own list of addresses it will not send to. If any recipient of a message is suppressed, Sendora refuses the whole message with `recipient_suppressed` and sends it to no one. The error lists the suppressed addresses and the stream. A [broadcast](https://sendora.se/docs/broadcasts) instead drops suppressed addresses and sends to the rest.

The calls on this page take `streamId`, and without it they mean the server's default transactional stream.

## How an address gets there

| Reason           | Added when                                                                                                                                                                                       | Who can lift it      |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------- |
| `hard_bounce`    | A receiver refused the address for good, for instance because the mailbox does not exist. The `bounced` webhook tells you which message.                                                         | You                  |
| `spam_complaint` | The recipient reported a message as spam, and the receiver told Sendora through its feedback loop. The `spam_complaint` webhook tells you.                                                       | Sendora support only |
| `unsubscribe`    | The recipient used the unsubscribe link of a message on a [broadcast stream](https://sendora.se/docs/broadcasts), or their mail client's one-click button. The `unsubscribed` [webhook](https://sendora.se/docs/webhooks) tells you. | Sendora support only |
| `manual`         | You added the address in the dashboard. The API cannot add one.                                                                                                                                  | You                  |

After one hard bounce, every later send to that recipient on the stream fails with `recipient_suppressed`. A soft bounce or a deferral never suppresses a recipient.

## Read the list

cURL:

```bash
curl 'https://api.sendora.se/v1/suppressions?limit=100' \
  -H "Authorization: Bearer $SENDORA_API_TOKEN"
```

TypeScript:

```ts
import { Sendora } from '@sendora/sdk';

const sendora = new Sendora({
  token: process.env.SENDORA_API_TOKEN,
});

const { suppressions } = await sendora.suppressions.list({
  limit: 100,
});

for (const entry of suppressions) {
  console.log(
    entry.address,
    entry.reason,
    entry.createdAt,
  );
}
```

Python:

```python
import os

from sendora import Sendora

sendora = Sendora(os.environ["SENDORA_API_TOKEN"])

page = sendora.suppressions.list(limit=100)

for entry in page.suppressions:
    print(entry.address, entry.reason, entry.created_at)
```

Response:

```json
{
  "suppressions": [
    {
      "streamId": "3d1a2b4c-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
      "address": "bounced@example.com",
      "reason": "hard_bounce",
      "messageId": "5f432ffd-c005-499b-aa3a-5b8a088ea20e",
      "createdAt": "2026-09-14T12:00:05.000Z"
    }
  ],
  "next": null
}
```

The list is newest first, in the page sizes on [Limits](https://sendora.se/docs/limits#page-sizes). Pass `next` as `after` for the next page. Each entry has the `streamId` of its list. To read another stream's list, pass that stream's `streamId` in the query. A stream of another server fails with `stream_not_found`.

Each stream's **Suppressions** tab, under its server's Streams tab in [Servers](https://app.sendora.se/servers), shows the list. There you add addresses, and lift the entries you may lift.

## Lift a suppression

Lift a hard bounce or a manual entry when the recipient can take mail again, for instance once they have confirmed a corrected mailbox. The address travels in the request body, never in a URL. `streamId` in the body names the stream, and without it the default one.

cURL:

```bash
curl -X POST https://api.sendora.se/v1/suppressions/delete \
  -H "Authorization: Bearer $SENDORA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "address": "bounced@example.com"
}'
```

TypeScript:

```ts
import { Sendora } from '@sendora/sdk';

const sendora = new Sendora({
  token: process.env.SENDORA_API_TOKEN,
});

await sendora.suppressions.delete({
  address: 'bounced@example.com',
});
```

Python:

```python
import os

from sendora import Sendora

sendora = Sendora(os.environ["SENDORA_API_TOKEN"])

sendora.suppressions.delete(address="bounced@example.com")
```

Lifting a spam complaint or the recipient's own unsubscribe fails with `spam_complaint_locked` or `unsubscribe_locked`. To have one lifted, write to [support@sendora.se](mailto:support@sendora.se) with the recipient's own request and the entry's `streamId` and `messageId` from the list. Leave the address out, since the stream and the message are enough to find the entry.

## Erasure requests

When a recipient asks you to erase their data, erase them with an account key. Every message to or from the address, sent and received, loses its content, and the address becomes a pseudonym in the log of every server.

cURL:

```bash
curl -X POST https://api.sendora.se/v1/erasures \
  -H "Authorization: Bearer $SENDORA_ACCOUNT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "address": "anna@example.com"
}'
```

TypeScript:

```ts
import { SendoraAccount } from '@sendora/sdk';

const account = new SendoraAccount({
  token: process.env.SENDORA_ACCOUNT_TOKEN,
});

const erasure = await account.erasures.create({
  address: 'anna@example.com',
});

console.log(erasure.erasureId, erasure.status);
```

Python:

```python
import os

from sendora import SendoraAccount

account = SendoraAccount(
    os.environ["SENDORA_ACCOUNT_TOKEN"]
)

erasure = account.erasures.create(
    address="anna@example.com"
)
print(erasure.erasure_id, erasure.status)
```

Response:

```json
{
  "erasureId": "6f1d2c3b-4a5e-4f60-8b7a-9c8d7e6f5a41",
  "status": "pending",
  "createdAt": "2026-10-04T12:00:00.000Z",
  "completedAt": null,
  "pseudonym": null,
  "messages": null,
  "receivedMessages": null
}
```

The erasure returns `pending`, and Sendora carries it out within a minute. [Read the erasure](https://sendora.se/docs/api/get-v1-erasures-id) to see it `done`, with the pseudonym and how many messages lost their content.

On the suppression lists, a hard bounce is removed. A spam complaint, an unsubscribe or a manual entry keeps only a keyed hash of the address, so the recipient stays protected from further mail without the address being stored. An erasure blocks nothing else: later mail to or from the address is sent and received as before.
