The list of addresses you must never mail again.
A suppression list holds every address your sending system refuses to deliver to: the ones that bounced for good, the ones whose owner reported you as spam, and the ones you added yourself. It is the part of email infrastructure nobody shows you in the pricing table, and it is the part that decides whether your domain still reaches the inbox in six months. Notix keeps one list per team, checks every send against it, and fills it for you from bounces and complaints.
Why the list has to exist before the first bounce.
Mailbox providers judge a sending domain on a small number of signals, and two of the strongest are the share of its mail that bounces and the share its recipients mark as spam. Both are ratios over what you send, so the fastest way to ruin them is to keep sending to addresses that have already told you no. A signup form with a typo produces one hard bounce. A nightly job that re-sends a reminder to every account with an unread notification turns that one bounce into thirty, and the complaint from a recipient who did not want your newsletter into a complaint every week.
Your application cannot be trusted to remember this on its own. The address lives in several tables, the sends come from several services, and the engineer who writes next year’s reminder job will not know about last year’s bounce. The list has to sit in the one place every send passes through, which is the sending service, and it has to be consulted without anyone asking.
The three reasons, and who adds them.
Every entry on the Notix list carries one of three reasons and, where there is one, the email that caused it.
| Reason | Added | What it means |
|---|---|---|
HARD_BOUNCE | Automatically, when the receiving server reports a permanent bounce. | The address does not exist or will never accept mail. Every recipient the bounce names is added, with the email that bounced recorded as the source. |
COMPLAINT | Automatically, when a recipient marks a message as spam. | Only the recipients who complained are added, not everyone on the message. The source is the email they complained about. |
MANUAL | By you, from the dashboard. | A customer who asked never to be emailed again, a role address, a list you brought from a previous provider. |
A soft bounce, where the mailbox is full or the server is temporarily unavailable, does not suppress anything; the transport retries it, and the message ends as delivered or as a bounce you see in the event log. Only a permanent bounce is treated as a verdict on the address.
What happens to a send that hits the list.
The check runs twice. When your request arrives, every recipient in to, cc and bcc is looked up. Suppressed copy recipients are dropped and the message goes to whoever is left; the other recipients asked for nothing and would be punished for somebody else’s complaint if the whole message were refused. Only when no deliverable recipient remains is the send refused: an email record is still created so you can see it, its status is SUPPRESSED, the reason is written to its events, no slot of your plan’s allowance is spent, and an email.suppressed event goes to your webhook.
The second check happens at the moment of sending. A scheduled message can sit in the queue for a month, and any recipient can bounce or complain in that window, so the list is re-read immediately before the message leaves rather than trusting the answer from the day it was created.
Follow the list from your webhook.
There is no public suppression endpoint today; the list is managed in the dashboard. The events that change it arrive on your webhook, so your own records can track it without polling.
// POST /webhooks/notix
export async function POST(request: Request) {
const event = await request.json();
switch (event.type) {
case "email.bounced":
if (event.data.bounce.type === "Permanent") {
// Notix has already suppressed these addresses. Mirror the state so
// your app stops offering them as a contact method.
await markUndeliverable(event.data.to, "hard_bounce");
}
break;
case "email.complained":
await markUndeliverable(event.data.to, "complaint");
break;
case "email.suppressed":
// A send you asked for never left: every To recipient was on the list.
await flagForReview(event.data.emailId, event.data.suppression);
break;
}
return new Response("ok");
}
@app.post("/webhooks/notix")
def notix_webhook():
event = request.get_json()
data = event["data"]
if event["type"] == "email.bounced" and data["bounce"]["type"] == "Permanent":
mark_undeliverable(data["to"], "hard_bounce")
elif event["type"] == "email.complained":
mark_undeliverable(data["to"], "complaint")
elif event["type"] == "email.suppressed":
flag_for_review(data["emailId"], data["suppression"])
return "ok"
{
"type": "email.suppressed",
"data": {
"emailId": "em_7f3k...",
"to": ["old-address@example.com"],
"suppression": {
"type": "Bounce",
"reason": "HARD_BOUNCE",
"source": "em_2a9c..."
}
}
}
One list for transactional and marketing mail.
This is the buying criterion that rarely makes it into a comparison table. Some providers keep transactional and marketing sends in separate products with separate lists, so a complaint about a campaign does nothing to stop the next receipt, and a bounce on a receipt does nothing to clean the next campaign. Notix has one list per team, and every send, from the transactional API, the SMTP relay, a campaign or a journey, is checked against it.
The one thing the list does not carry is unsubscribes, and that is on purpose. Unsubscribing is a preference held on the contact: a campaign or journey send to an unsubscribed contact is refused, while a transactional send to the same address still goes out, because a person who stopped wanting your newsletter has not asked to stop receiving their password reset. Marketing sends carry the List-Unsubscribe and List-Unsubscribe-Post headers, so Gmail and Yahoo can offer their one-click unsubscribe and the contact is unsubscribed rather than driven to the spam button, which would have put them on the suppression list instead.
Managing the list.
The dashboard shows the list with its reason and source, lets you search it, filter it by reason, add an address as MANUAL, and remove one. Removing an address that bounced also asks the transport to forget the bounce, so the next send is a genuine attempt. Do that when you know the address is live again; do not do it to a complaint because you would like to mail the person, which is how a domain acquires a reputation problem it cannot see.
Moving from another provider, export its bounces and spam reports and add them by hand before the first send from the new domain. The old provider’s history does not travel with you, and a new domain that opens by mailing a known-bad address is making the worst first impression it can. Unsubscribes go to the contacts, imported with subscribed off, not to the suppression list.
Questions, answered.
What is a suppression list and why do I need one?
Is there a suppression list API?
What happens when I send to a suppressed address?
Is unsubscribing the same as suppression?
Can I remove an address from the suppression list?
How do I move my suppression list from SendGrid, Mailgun or Postmark?
Keep reading.
Email bounce handling
Hard bounces against soft bounces, what happens to the address automatically, and the bounce webhook payload your code receives.
LearnEmail deliverability and sender reputation
What mailbox providers score, the complaint threshold that matters, warming a new domain, and the honest position on shared IPs.
ProductTransactional email API
OTPs, receipts and alerts with idempotency keys, a deliverability pre-check and a shared suppression list.
CompanySecurity
How Notix protects sending credentials, customer data and mail in transit.
NotixDocs
The quickstart: verify a domain, copy an API key, send the first email.
Send with the list already in place.
Bounces and complaints are suppressed automatically from the first message. The webhook events are in the docs.