Suppression Lists and Bounce Handling for AI Senders
2026-04-20
A suppression list is one of the most important things in email infrastructure. It's also one of the most commonly misimplemented.
The idea is simple: maintain a list of addresses that should never receive email. Check it before every send. If the address is on the list, don't send.
In practice, suppression lists fragment. Your marketing team has one list. Your transactional email has another. Your support tool has a third. A customer who opted out of marketing email still gets transactional sequences. A contact who hard-bounced from one workflow still gets messages from another because the bounce wasn't propagated. By the time the suppression failure causes a real problem - a complaint, a CAN-SPAM violation, a lost account - the source is nearly impossible to trace.
AI agents make this worse. An agent that spins up a new workflow doesn't know about the suppression decisions made by previous workflows, by human operators, or by other agents. Unless suppression is enforced at the infrastructure layer - checked automatically on every send regardless of which agent or workflow originates it - the list is only as good as the discipline of whoever built each individual workflow.
The suppression categories that matter
Suppression entries come from different sources and carry different weights. Understanding the categories helps when deciding how to configure your own lists.
Hard bounces (global DNC). A hard bounce means the address doesn't exist or the domain permanently rejects mail. Continuing to send to a hard-bounced address damages your sender reputation without any possibility of reaching anyone. Hard bounces should be added to the global do-not-contact list automatically when the bounce event arrives. They should never be removed unless you have strong evidence the address is now valid (which is rare).
Spam complaints. When a recipient marks an email as spam, that's a signal that they don't want your mail. The complaint rate Gmail and Yahoo track is one of the primary inputs into sender reputation scoring. Industry guidance is to keep complaint rates under 0.1%. A complaint should trigger immediate suppression of the complaining address - not after a review process, not after a human makes a decision. Automatically.
Role accounts. Addresses like admin@, info@, postmaster@, support@, and noreply@ are not inboxes for a specific person. Sending to them generates bounces and complaints without reaching anyone who wanted your email. They should be suppressed pre-emptively.
Legal and compliance requests. Unsubscribe requests, GDPR deletion requests, and explicit do-not-contact instructions are legal obligations in many jurisdictions. These require immediate suppression and an audit trail showing when the suppression was added and why.
Manual do-not-contact. Contacts who asked to stop receiving email through any channel - a reply, a support ticket, a phone call - should be added manually. These are separate from automated suppression events because they require human judgment to identify.
Domain-level suppressions. Sometimes entire domains should be suppressed - a competitor's domain, a known spam trap domain, a domain that has repeatedly bounced. Domain suppressions prevent sending to any address at that domain without requiring individual address entries.
What bounce handling looks like
Bounce handling is the process of receiving delivery status events from your email provider and acting on them. The events arrive as webhooks.
A hard bounce webhook typically looks like this:
{
"event": "bounced",
"recipientEmail": "nonexistent@example.com",
"bounceType": "hard",
"bounceCode": "5.1.1",
"timestamp": "2026-04-20T10:30:00Z"
}
The correct response to a hard bounce is:
- Add the address to the global suppression list with
reasonCode: "hard_bounce" - Update the contact record to reflect the bounce status
- Cancel any pending scheduled sends to this address
For soft bounces (temporary delivery failures), the correct response is different: retry the delivery with exponential backoff, and only add to the suppression list if the address soft-bounces consistently over multiple attempts. A single soft bounce doesn't mean the address is invalid.
Complaint handling follows the same pattern but with more urgency:
{
"event": "complained",
"recipientEmail": "upset@example.com",
"timestamp": "2026-04-20T11:15:00Z"
}
Suppress immediately, no questions asked. The complaint rate calculation from Gmail and Yahoo doesn't distinguish between "we reviewed this and suppressed them in 24 hours" and "we suppressed them immediately." Both count as a complaint. Only one keeps your reputation intact.
Why AI agents need infrastructure-level suppression
When a human sends email, the suppression check is usually part of the same UI that initiates the send. A marketer using a campaign tool sees "this list has 5,000 contacts, 200 suppressed" before they click send. The check is visible.
When an agent sends email, there's no UI and no human making a decision at send time. The agent identifies a recipient, composes content, and calls the send API. The suppression check either runs automatically at the infrastructure layer - before the email leaves - or it doesn't run at all.
This is the core problem with building suppression into the agent itself. You'd need every agent that sends email to:
- Know which suppression lists exist
- Query those lists before every send
- Handle the case where the list service is unavailable
- Keep the query consistent across restarts and deployments
- Handle edge cases (domain suppressions, legal suppression scopes)
That's a significant amount of logic that has to be duplicated across every agent, every workflow, and every system that touches email. And when it's implemented in application code rather than infrastructure, it can be bypassed - accidentally by a developer who forgot to include the check, or deliberately by a misconfigured agent.
Infrastructure-level suppression runs the check as part of the send pipeline, regardless of what called it. The agent can't forget to check. The check can't be bypassed by omission. The suppression list is the same list, regardless of which workflow or agent originates the send.
How suppression scope works
Not every suppression applies to every send. The scope of a suppression determines which sends it blocks:
Global - Blocks all sends to this address from any mailbox, any tenant, any workflow. Hard bounces and spam complaints are typically global. A contact who hard-bounced is not reachable by anyone on the platform.
Tenant - Blocks sends to this address from your organization. A manual do-not-contact entry from a customer conversation would be tenant-scoped - they don't want to hear from you specifically, but there's no reason to block them globally.
Campaign - Blocks sends for a specific campaign or sequence. A contact who unsubscribed from your onboarding sequence but is still active for support email would have a campaign-scoped suppression.
When a send is evaluated, all applicable scopes are checked. A tenant-level suppression blocks the send even if no global suppression exists.
Checking suppression before high-stakes sends
For sends where the suppression status of a contact needs to be verified before committing to a workflow, you can query the suppression status directly:
GET /v1/suppressions?tenantId=your-tenant-id&recipientEmail=contact@example.com
Authorization: Bearer mm_live_...
Or use the simulate-send endpoint for a full pre-send policy check that includes suppression:
POST /v1/agent/simulate-send
Authorization: Bearer mm_live_...
{
"tenantId": "your-tenant-id",
"mailboxId": "mbx_abc123",
"recipientEmail": "contact@example.com",
"templateId": "campaign-template",
"dedupeKey": "campaign-contact-step1"
}
The simulate response shows whether the send would be allowed and, if not, which suppression entry is blocking it and why:
{
"wouldAllow": false,
"reason": "suppressed",
"suppressionInfo": {
"scope": "global",
"reasonCode": "hard_bounce"
}
}
This is useful for agents that need to make decisions before sending - routing a contact to a different channel, removing them from a sequence, or flagging them for human review - rather than discovering the suppression from a blocked send response.
Reputation thresholds and auto-pause
When bounce and complaint rates exceed configured thresholds, Molted automatically pauses the mailbox. This is the risk budget in action: rather than letting a bad send event damage your domain reputation indefinitely, the mailbox stops accepting sends and requires manual review before resuming.
The reputation check runs per-mailbox, so a poorly-performing campaign doesn't take down your transactional email. Keeping different workflows on separate mailboxes - outbound prospecting on one, transactional on another, dunning on a third - means that reputation issues are isolated to the mailbox where they originate.
When a mailbox is auto-paused, you can review the reputation metrics, address the underlying issue, and then manually unpause:
POST /v1/me/mailboxes/:id/unpause
The pause is a circuit breaker, not a permanent ban. But the threshold exists for a reason: if your bounce or complaint rate has hit the ceiling, sending more email before fixing the underlying problem makes the reputation damage worse.
Suppression lists and bounce handling are not optional features. They're the mechanism that keeps your domain out of blocklists, your complaint rate below the threshold that degrades inbox placement, and your legal exposure manageable.
For AI agents, the only suppression that's reliable is suppression enforced at the infrastructure layer - where it runs on every send, regardless of which agent or workflow originated it.
Molted checks all suppression categories automatically on every send. If you're building agents that send email, start your free account or read the docs to see how the policy engine works.
For the broader picture of deliverability risks specific to AI agents, Email Deliverability for AI Agents: A Technical Guide covers the full range of signals that affect inbox placement.