Suppressions
How addresses land on your suppression list, what happens when you send to them, and how to list, add, and remove entries.
A suppression is an address Mailfully will not deliver to. Entries are created automatically from hard bounces and spam complaints, or manually. The list is org-global: one list covers both your test and live environments.
What gets suppressed automatically
| Trigger | Reason recorded |
|---|---|
| Permanent (hard) bounce | hard_bounce |
| Spam complaint | complaint |
Transient and undetermined bounces never suppress. A soft bounce adds no entry, changes no message status, and emits no webhook. Mailfully stores every hard-bounced or complained address lowercased and mirrors each entry to the underlying SES account-level suppression list.
Sending to a suppressed address
Sends to suppressed addresses are not rejected. You get no error. At accept time, suppressed recipients are silently dropped from to, cc, and bcc:
- Some recipients suppressed: the message sends to the remaining recipients.
- All
torecipients suppressed: you still get202and a message id, but the message is persisted with statuscanceled. Nothing is sent, and the message is never metered.
A race window also exists: an address can be suppressed between accept and send (for example, by a hard bounce landing moments earlier). A pre-send guard re-checks every recipient immediately before dispatch. If all to recipients are suppressed by then, the message flips to status failed with last_event: "suppressed", and a synthetic suppressed event listing every dropped recipient is written to the message's event timeline.
A 202 means Mailfully accepted the request, not that mail went out. If you need to know whether a message was actually sent, poll GET /v1/emails/:id for its status, or subscribe to webhooks.
List and filter suppressions
Listing requires the read:suppressions scope, which can be minted onto an API key. An mf_ key works here.
curl "https://api.mailfully.com/v1/suppressions?email=ada@example.com" \
-H "Authorization: Bearer mf_live_xxxxxxxxxxxx"{
"data": [
{
"id": "01J1F5S8ZG9Q2W7X4V3B2N1M0K",
"email": "ada@example.com",
"reason": "hard_bounce",
"source": "ses_notification",
"created_at": "2026-07-08T14:23:07.123Z"
}
],
"has_more": false,
"next_cursor": null
}
Query parameters:
email: exact match. Stored values are canonical lowercase, so lowercase your query or it will not match.reason: exact match againsthard_bounce,complaint, ormanual.limit: default 25, max 100.cursor: opaque cursor from a previous page'snext_cursor.
See List suppressions for the full schema.
Add a suppression manually
curl -X POST https://api.mailfully.com/v1/suppressions \
-H "Authorization: Bearer <session token>" \
-H "Content-Type: application/json" \
-d '{ "email": "ada@example.com" }'
{
"id": "01J1G0Q4RS7T9V2W5X8Y1Z3A6B",
"email": "ada@example.com",
"reason": "manual",
"source": "dashboard",
"created_at": "2026-07-08T15:01:44.502Z"
}
Adding and removing entries needs the session-only manage:suppressions scope, so an mf_ key gets 403 insufficient_scope here. See Authentication.
The add is idempotent: a new entry returns 201, and adding an address that is already suppressed returns 200 with the existing entry. The email is trimmed and lowercased before storing. See Create suppression.
Remove a suppression
curl -X DELETE https://api.mailfully.com/v1/suppressions/01J1F5S8ZG9Q2W7X4V3B2N1M0K \
-H "Authorization: Bearer <session token>"
{
"id": "01J1F5S8ZG9Q2W7X4V3B2N1M0K",
"deleted": true
}
When the entry was synced to SES, Mailfully also clears the SES-level block if no other suppression still covers that address, then deletes the entry. The call fails closed: if SES cannot be updated, the request returns 503 service_unavailable and the entry stays intact. Retry the delete. See Delete suppression.
Think twice before removing a hard_bounce entry. The address permanently rejected your mail; sending to it again will most likely hard-bounce again, and the next permanent bounce re-suppresses it. Remove hard-bounce entries only when you know the mailbox has changed — a typo fix, a re-created account.
Reason values
| Reason | Written by | Source value |
|---|---|---|
hard_bounce | Permanent bounce | ses_notification |
complaint | Spam complaint | ses_notification |
manual | POST /v1/suppressions | dashboard |