Hoppa till innehållet

After sending

Suppressions

Each stream 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 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

ReasonAdded whenWho can lift it
hard_bounceA receiver refused the address for good, for instance because the mailbox does not exist. The bounced webhook tells you which message.You
spam_complaintThe recipient reported a message as spam, and the receiver told Sendora through its feedback loop. The spam_complaint webhook tells you.Sendora support only
unsubscribeThe recipient used the unsubscribe link of a message on a broadcast stream, or their mail client’s one-click button. The unsubscribed webhook tells you.Sendora support only
manualYou 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

GET /v1/suppressions?limit=100
curl 'https://api.sendora.se/v1/suppressions?limit=100' \
  -H "Authorization: Bearer $SENDORA_API_TOKEN"
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,
  );
}
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

{
  "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. 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, 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.

POST /v1/suppressions/delete
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"
}'
import { Sendora } from '@sendora/sdk';

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

await sendora.suppressions.delete({
  address: 'bounced@example.com',
});
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 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.

POST /v1/erasures
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"
}'
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);
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

{
  "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 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.