Sending
Suppressions
An address that hard bounces or files a complaint is suppressed immediately. Sending to a suppressed address returns 422 suppressed before anything is written — you find out at the API, not from a bounce an hour later.
Suppressions are per account
A suppression on your account stops your mail to that address. It does not stop anybody else’s: another Posthaste customer with a legitimate relationship with the same person is unaffected, which is correct — a bounce from your list says something about your list, not about the address in general.
There is a second, narrower kind. A platform suppression, marked "scope": "platform", applies to every account on the infrastructure. Those are added by us, for addresses that endanger the sending reputation everyone shares — spam traps, and addresses that have demonstrated the same. They appear in your list so that a 422 is explicable, and no account can remove one.
Reasons
| Reason | Meaning |
|---|---|
| hard_bounce | The receiving server permanently refused the address — no such mailbox, no such domain. Added automatically, and by far the most common reason. |
| complaint | The recipient reported the message as spam. Added automatically. Cannot be removed. |
| manual | You added it yourself through the API or the dashboard. |
| unsubscribe | The recipient used an unsubscribe mechanism we handled. |
| spam_trap | The address was identified as a spam trap. Sending to one is a fast route to a blocklist. |
A temporary failure never suppresses. A mailbox that was full for an afternoon, greylisting, a rate limit at the receiving end — all of those are deferrals, retried on a backoff. Suppressing on a transient error would make a working recipient permanently unreachable, and you would never find out why.
List suppressions
/v1/suppressionssuppressions:readNewest first, keyset-paginated. See pagination.
| Parameter | Type | Notes |
|---|---|---|
| limit | integer optional | 1–200, default 50. |
| before | string optional | A sup_ id — the nextCursor from the previous page. |
| search | string optional | 1–320 characters, matched anywhere in the address. People remember a domain, not a whole address. |
| reason | string optional | One of the five above, spelled exactly. Anything else returns 400 invalid_request. |
// One page.
const page = await posthaste.suppressions.list({ reason: 'complaint', limit: 100 })
// Or every page.
for await (const entry of posthaste.suppressions.autoPaginate({ reason: 'hard_bounce' })) {
entry.address
entry.scope // 'account' — yours to remove — or 'platform', which is not
}detail carries whatever explanation exists — for a bounce, the receiving server’s own diagnostic text. scope is account or platform, said here so you do not discover the difference from a 422 on delete.
Add one
/v1/suppressionssuppressions:writeFor addresses you know you should not mail — an in-app opt-out, a customer request, an address your own system has retired.
| Field | Type | Notes |
|---|---|---|
| address | string required | 3–320 characters. Normalised before storage, so casing and equivalent forms match. |
| reason | string optional | Up to 500 characters of free text. It is stored as the entry’s detail, not as its reason — a suppression you create always has reason manual. Write a note your future self can act on. |
await posthaste.suppressions.create({
address: '[email protected]',
// Free text. Stored as the entry's DETAIL — the reason is always 'manual'.
reason: 'asked to be removed by email',
})| Status | When |
|---|---|
| 201 | { address, reason: "manual" }. Adding an address that is already suppressed is a no-op and still returns 201 — the end state is what was asked for. |
| 422 invalid_address | The value is not an email address. |
| 400 invalid_request | The field is missing or out of range. |
Remove one
/v1/suppressions/:addresssuppressions:writeThe path segment is the address, URL-encoded — not a sup_ id. Removing one is appropriate when you know the underlying problem is fixed: a mailbox that has been recreated, an opt-out the customer has reversed.
// The ADDRESS, not a sup_ id. The SDK url-encodes it for you.
await posthaste.suppressions.delete('[email protected]')
// Refused with 422 for a complaint (suppression_protected) or a
// platform-wide entry (suppression_platform).| Status | When |
|---|---|
| 204 | Removed. |
| 404 not_found | That address is not suppressed on this account. |
| 422 suppression_protected | The entry’s reason is complaint. It can never be removed. Somebody marked your mail as spam; sending to them again is what gets a sending IP blocklisted, and the IP is shared. |
| 422 suppression_platform | A platform-wide entry. Not removable by an account. Contact support if you believe it is wrong. |
Do not loop over your suppression list removing entries. It is the single fastest way to damage your own delivery. Fix hard bounces at the source — a list that keeps producing them is a list with a collection problem, and re-mailing it makes the next bounce rate worse, not better.
NextSending limits →The monthly allowance, your account’s daily cap, and how the cap moves.