Suppressions
A suppression is an address Anypost will not deliver to. The list is your team's, and it protects your sending reputation by stopping mail to addresses that bounced, complained, or opted out.
How an address gets suppressed
Most suppressions are added automatically. You can also add one yourself.
reason | Added when |
|---|---|
permanent_bounce | A receiving server permanently rejected delivery, usually a non-existent address. |
complaint | A recipient marked a message as spam. |
unsubscribed | A recipient used a one-click unsubscribe link, or opted out through their mailbox provider's feedback report. |
manual | You added the address through the API or dashboard, or imported it from a file without a reason Anypost recognizes. |
A complaint or a stream of bounces damages how mailbox providers see your domain. Suppressing those addresses on the first signal is what keeps the rest of your mail in the inbox.
Topic scope
Every suppression is scoped to a topic, and the scope decides which sends it blocks.
- A global suppression has the topic
*. It blocks every send to that address. Bounces and complaints always write a global suppression: a dead address is dead for all mail. So does an opt-out reported by a mailbox provider, which names no topic. - A topic-scoped suppression names one topic, such as
marketing. It blocks only sends carrying that sametopic. A one-click unsubscribe writes one of these, scoped to the topic the recipient unsubscribed from.
This scoping is the transactional carve-out. A recipient who unsubscribes from
marketing is suppressed for marketing only, so a later password reset or
one-time code, sent with a different topic or none at all, still reaches
them. A send with no topic is checked against global suppressions only. See
Tags, topics & campaigns.
What happens on a send to a suppressed address
When a send names an address that is suppressed for that send's topic, the
address is dropped before delivery. The rest of the recipients are unaffected,
and you are not billed for the dropped recipient. Anypost emits an
email.suppressed event so the outcome is visible on your webhooks.
Listing suppressions
GET /v1/suppressions returns the list, newest first, with cursor pagination.
The TypeScript list returns a page you can iterate to walk every page:
curl https://api.anypost.com/v1/suppressions \
-H "Authorization: Bearer $ANYPOST_API_KEY"Narrow the list with query parameters:
| Parameter | Restricts to |
|---|---|
email_contains | Addresses containing this substring. |
topic | One topic. Pass * for global entries only. |
reason | permanent_bounce, complaint, unsubscribed, or manual. |
origin | auto for automatic entries, manual for ones you added. |
To check one address, GET /v1/suppressions/{email} returns every record on
file for it, across all topics. The {email} segment is URL-encoded.
Adding a suppression
POST /v1/suppressions adds an address yourself, for example on a request
from a customer:
curl https://api.anypost.com/v1/suppressions \
-H "Authorization: Bearer $ANYPOST_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"topic": "marketing",
"note": "customer requested removal"
}'topic is optional and defaults to *, a global suppression. Set a specific
topic to block only that stream. note is an optional internal annotation.
Adding an address that is already suppressed for the same (email, topic) pair
returns 422.
Adding in bulk
POST /v1/suppressions/batch adds up to 1,000 addresses per call. Each item
takes the same email, topic and note as a single add, plus an optional
reason that maps the same way as an import's reason column:
curl https://api.anypost.com/v1/suppressions/batch \
-H "Authorization: Bearer $ANYPOST_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"suppressions": [
{ "email": "[email protected]", "reason": "hard bounce" },
{ "email": "[email protected]", "topic": "marketing", "reason": "unsubscribed" }
]
}'{ "imported": 2, "already_suppressed": 0, "invalid": [] }Unlike a single add, an address already suppressed for that topic is counted in
already_suppressed and left unchanged instead of returning 422, so a batch
is safe to retry. An email that is not a valid address is listed in invalid
with its position; the rest of the batch still goes through. A batch is not an
import: it has no undo, so remove entries with DELETE. A batch that would take
you past your suppression limit returns 422 and adds nothing.
Importing a list
Moving from another provider? Bring its suppression list with you, so the first send through Anypost does not mail addresses that already bounced, complained, or unsubscribed there.
- Export the list from your previous provider as CSV. Export bounces and complaints together if you can; export each unsubscribe list on its own.
- In the dashboard, open Suppressions and choose Import.
- Pick the file. Anypost reads the column headed
email(oremail_address,address,recipient), or the first column holding addresses. A plain file with one address per line works too. An optional column headedreasonkeeps each address's reason (see below). - Leave Topic blank for bounces and complaints. For an unsubscribe list from one mailing list, set the topic that list maps to, so the rest of your mail still reaches those recipients.
Keep the tab open until the import finishes. One import takes up to 1,000,000 rows; for a larger list, contact [email protected]. Imported addresses count toward your suppression limit. An import that would go past it stops at that point and keeps what it added before.
| Result | Meaning |
|---|---|
| Added to your list | Suppressed now, with the reason from the file, or manual. |
| Already suppressed | Already on your list for that topic, or repeated in the file. The existing entry is unchanged. |
| Not a valid address | Skipped. |
The reason column takes our values (permanent_bounce, complaint,
unsubscribed, manual) and the words other providers export, ignoring case,
spaces and punctuation:
| File says | Imported as |
|---|---|
bounce, bounced, hard bounce | permanent_bounce |
complaint, complained, spam complaint, spam report | complaint |
unsubscribe, unsubscribed, opt-out | unsubscribed |
Blank, or anything else (an SMTP response, soft bounce) | manual |
Every imported address is suppressed whatever its reason; the reason only
labels it in your list and in email.suppressed events.
Imported addresses are enforced within 30 seconds. Recent imports on the same page lists each import with its counts. Undo removes the addresses that import added, and is available for 7 days after the import starts. Addresses that were already suppressed before the import, or that bounced or complained after it, stay suppressed. To reverse an older import, contact [email protected].
Limits
Each team can hold as many suppressions it adds itself (by import, the API, or the dashboard) as its plan sends in a month, and at least 10,000. A team on a 1,000,000-email plan can add 1,000,000. The count covers every reason you set, including bounces and complaints you import. Suppressions Anypost adds from your own sending (bounces, complaints, and unsubscribes) never count, so they never stop.
The Suppressions page shows how much of the limit you use. Removing a
suppression or undoing an import frees room. An add that would go past the limit
returns 422 and adds nothing. Upgrade your plan, or contact
[email protected] to raise the limit.
Removing a suppression
Removing an address makes it eligible to receive mail again on the next send.
DELETE /v1/suppressions/{email}removes the address across every topic.DELETE /v1/suppressions/{email}/{topic}removes one topic's entry and leaves the others. Use%2Afor the global topic*.
Removal does not stop a fresh suppression later: a future bounce, complaint, or unsubscribe for that address writes a new record. Lift a suppression only when you have reason to believe the address is good again.
Expiry
Suppressions do not expire. Every entry, whatever its reason, stays enforced until you remove it.
Where to go next
- Tags, topics & campaigns: the topic that scopes a suppression.
- Unsubscribe handling: how a one-click unsubscribe creates a topic-scoped suppression.
- Webhooks: receive
email.bounced,email.complained, andemail.suppressedevents.