Suppression-List Architecture for Sending Platforms
How a multi-tenant platform scopes suppression — global vs account vs tenant vs stream — with auto-suppression triggers, precedence and override semantics, retention, and bulk transfer, extracted from AWS SES's documented design.
Operational9 min read
Who it is for ESP operators
ContentsOn this page — 6 sections
If your platform sends mail for many customers, you have to decide where each do-not-send list applies, what adds addresses to it, and how an exception can override it. The best public evidence for these decisions is Amazon SES, which documents a complete scheme with four levels, and the patterns below are attributed to it.
What to suppress for a single sender, and why, is covered in Reputation Monitoring, suppression lists and Complaint Feedback Loops. The focus here is the platform architecture: scopes, precedence, triggers, retention and transfer.
The scope hierarchy (SES's four levels)
| Scope | Who it protects | What adds addresses | Visible to the customer? | Retention |
|---|---|---|---|---|
| Global (the whole platform) | The platform itself, across all customers | Hard bounces from any customer's sending | No. It cannot be queried, edited or disabled | A retention period that grows with each bounce, 14 days at most |
| Account (one customer) | One customer account | Hard bounces, complaints or both from that account's sending; manual and bulk additions | Yes, with full create, read, update and delete operations and bulk import and export | Until removed (automatically purged after 90 days if the account's sending is paused) |
| Tenant (one sub-customer) | One tenant within an account | That tenant's own bounces and complaints, when tenant scope is enabled | Yes, with the same API and a tenant parameter | Until removed; deleted with the tenant |
| Stream (one configuration set) | One sending workflow | Nothing. It only overrides: it redirects or disables checking and recording for sends that use that stream | Yes, as settings rather than a separate list | n/a |
The general pattern is a short-lived global backstop, controlled by the platform, for provable delivery failures; long-lived lists controlled by customers for everything else; and overrides for each stream to handle exceptions.
Global (platform-wide) suppression (SES pattern)
- Trigger. A hard bounce from any customer's send adds the address for all customers. Nothing else, including complaints, feeds the global list.
- Growing retention. After a first hard bounce, the address is suppressed for a short period and then removed automatically. Each later hard bounce adds it again for a longer period, up to a maximum of 14 days on the list. The global list is therefore a cache of addresses recently known to be bad, not a permanent register. This deliberately avoids suppressing, permanently and for every customer, addresses that may become valid again.
- No visibility. Customers cannot query it, add to it or disable it. The only sign of it is the synthetic bounce (below).
- Sending behavior. The API accepts a send to a globally suppressed address but does not transmit it. The platform generates a synthetic bounce (
bounceType=Permanent,bounceSubType=Suppressed). Importantly, these synthetic bounces count toward the customer's bounce rate and daily quota. Mailing suppressed addresses still costs the customer reputation standing, which keeps the incentive to clean lists. - Override. A customer's own account-level list takes precedence for their sending decisions. An address on the global list but not on the customer's account list will still be attempted if the customer sends to it, but a resulting bounce counts against the customer. SES used to offer a form for customers to request removal from the global list; it was retired in favor of account-level lists.
Design lesson. Should customer B be protected from an address that hard-bounced for customer A? The global scope answers yes, briefly, and only for delivery failures. Complaints never cross that line: they stay within the account or tenant that received them. This is the vendor's answer to the question of suppression across customers.
Account-level suppression (SES pattern)
- On by default. Accounts created after November 25, 2019 have it enabled for both bounces and complaints. Older accounts opt in (
PutAccountSuppressionAttributes). - Triggers (
SuppressedReasons).BOUNCE(hard bounces only; soft bounces never add an address automatically),COMPLAINT(spam reports from feedback loops (FBLs)), or both. Each entry records its reason, the feedback event that triggered it, and the message that caused it. - Matching reasons. An entry blocks a send only when its reason matches the reasons configured for the account. With the setting Bounces only, entries with the reason
Complaintare still mailed. With Bounces and Complaints, both kinds of entry block. - Effect on metrics. Sends blocked by the account list do not count toward the account's bounce and complaint rates for reputation (they appear in separate suppression counters), but they do use daily sending quota. The list protects reputation; it does not provide free volume.
- Propagation. Hard bounce entries added to the account list are also added to the global list, so one customer's verified bad address briefly protects everyone.
- Retention. Entries stay until they are explicitly removed. If the account's sending is paused (as an enforcement action), the platform automatically deletes the account list after 90 days, unless sending is restored first.
- A known blind spot. Gmail sends no complaint feedback to SES, so a Gmail user's click on "spam" never adds an address to complaint suppression, at any scope. Any suppression design must assume that complaint data is incomplete by nature for some major providers. See Google Postmaster Tools for the aggregate data that partly replaces it.
- A storage detail to copy deliberately or to avoid. Addresses are stored with their original capitalization. Matching at send time ignores case, but calls to the management API need the exact case.
- No size limit applies to the list itself.
Stream-level (configuration-set) overrides
A setting for each stream can override account suppression in three ways (SES's "suppression list options"):
- Inherit: the stream uses account-level suppression unchanged.
- Disable entirely: the stream bypasses all suppression ("override account settings" with suppression turned off). This is the mechanism the platform provides for the transactional exception, because a person who complained must still receive their receipts and tickets (see Complaint FBLs), and for deliberate sends that check addresses again.
- Custom reasons: the stream applies its own set of reasons and ignores the account settings. For example, the marketing stream suppresses on bounces and complaints while the account default is bounces only.
Scoping also applies to additions. Account suppression can be set to record new entries only from sends tagged with specific configuration sets.
Tenant-level suppression (SES pattern, for isolating tenants)
By default, all tenants in an account share the account-level list, so a bounce or complaint from one tenant suppresses the address for every tenant. Tenant-level suppression gives each tenant its own separate list. Two settings are set together, both or neither:
SuppressionScope:TENANTuses the tenant's own list;ACCOUNT, the default, uses the shared account list.SuppressedReasons:BOUNCE,COMPLAINT, both, or empty, which means no checking and no recording.
How the combinations behave, as documented:
| Scope | Reasons | Check at send time | Recording |
|---|---|---|---|
| TENANT | BOUNCE, COMPLAINT | Tenant list, both reasons | Both, to the tenant list |
| TENANT | BOUNCE | Tenant list, bounces only | Bounces, to the tenant list |
| TENANT | COMPLAINT | Tenant list, complaints only | Complaints, to the tenant list |
| TENANT | (empty) | none | none |
| ACCOUNT | BOUNCE, COMPLAINT | Account list, both reasons | Both, to the account list |
| ACCOUNT | (empty) | none | none |
The rules that matter:
- Precedence. The configuration set overrides the tenant, which overrides the account. A stream override can change only the scope, only the reasons, or both, without changing the tenant defaults.
- Scopes replace each other; they do not add up. With scope
TENANT, the account list is skipped entirely, so an address on the account list but not on the tenant list is mailed. Isolation works in both directions: the tenant escapes contamination from other tenants and loses the shared protection. - Bounces and complaints are recorded differently. Under tenant scope, hard bounces are recorded to the tenant list and the global list (never the account list), and complaints go to the tenant list only. Delivery failures still feed the platform-wide backstop, while behavioral signals stay private to the tenant.
- Automatic removal. When a recipient marks a message they previously reported as not spam, the matching
COMPLAINTentry is removed from the tenant list automatically. - Observability. Blocks caused by tenant suppression are labeled: bounce type
Permanentwith subtypeOnTenantSuppressionList, the diagnostic code "…on the suppression list for your tenant", and ases:tenant-nametag on bounce and complaint events for attribution. - Structure. Each tenant has exactly one list (1:1). Lists are specific to a region. Deleting the tenant deletes its suppression entries. Blocked sends still count against sending quota. The same case-sensitivity rule applies. The API operations are the same as at account level, with a
TenantNameparameter; leaving it out targets the account list, so existing integrations keep working.
Bulk transfer: import and export mechanics (SES pattern)
Moving suppression lists matters when customers change platforms. A customer who arrives should import their previous suppression list before the first send, and a customer who leaves should be able to take it with them. SES documents these mechanics:
- Import (add). A CSV file (
address,REASON) or newline-delimited JSON ({"emailAddress":…,"reason":…}) from object storage. Up to 100,000 addresses per import job, and at most 20 concurrent jobs. The reasons are limited toBOUNCEandCOMPLAINT. Each job has a status with counts of processed and failed records, and a failure file for reconciliation. - Bulk delete. The same pipeline with a delete action, limited to 10,000 addresses per job.
- Export. A paginated listing API with
StartDateandEndDatefilters (entries added after or before a timestamp), which supports both a full export and incremental synchronization. - Bulk operations require production account status, meaning the account has been vetted. This is a control against platform abuse, because bulk import or removal of suppression entries can also be used to clean bad lists and to probe addresses.
What an ESP should consider in a transfer. Keep the reason for each entry across the transfer, because bounces and complaints behave differently under overrides. Keep where each entry came from (date, triggering event) where possible. Treat incoming bulk jobs that remove addresses from suppression with more suspicion than jobs that add them. Legal limits on transferring addresses of people who opted out apply to how the platform handles exported lists: CAN-SPAM prohibits selling or transferring an address after the recipient opts out, other than sharing it for suppression.
Architecture decisions the vendor evidence settles
-
Scope complaints narrowly and bounces more broadly. In the SES design, complaints never leave the account or tenant that received them. Only hard bounces, which are objective delivery failures, spread across the platform, and even then for ≤14 days. A person who complained about customer A is not suppressed automatically for customer B.
-
There are exactly two triggers for automatic suppression: a hard bounce and an FBL complaint. Soft bounces never add an address automatically at any scope. Suppressing after a threshold of soft bounces, for example after several in a row, is a policy for the sender to set (see Reputation Monitoring). In this design, list management handles unsubscribes, not the platform's suppression layer.
-
Every scope needs a way to override it, with explicit, documented behavior (inherit, disable or custom), because the transactional exception is real. Make the bypass a setting for each stream, not a flag on each send, so that it can be audited.
-
Suppressed sends must stay visible and must have a cost. Emit distinct events (dedicated bounce subtypes or reason codes) so customers can see suppression working, and count suppressed attempts against quota so that suppression does not become free volume. Exclude sends suppressed by the platform from the customer's reputation metrics, because the block prevented the harm.
-
Retention differs by scope on purpose. Platform-global retention lasts days, so the list heals itself. Customer and tenant lists last until someone acts on them, and their cleanup follows the account lifecycle (a purge 90 days after an enforcement pause; deletion with the tenant).
Keeping unsubscribes forever conflicts with data protection erasure, and that separate legal design problem, raised in the contexts of CASL and PECR, is outside the sources used here. It is resolved on the legal side in GDPR and ESP Suppression Lists, which explains when suppressing an address without the client's instruction turns the ESP from a Data Processor into a Data Controller, and why a minimal suppression record survives an erasure request. See also Right to Object and Erasure.
-
Isolation is explicit and must be switched on. The default is a list shared across the account, which gives the most protection. Tenant isolation is enabled for a tenant when the risk of contamination from other tenants outweighs the shared protection, and the platform states plainly that isolated tenants lose the protection of the account list.
For the tenant container itself (reputation policies, automatic pauses), see Multi-Tenant ESP Architecture.
Check your own record
The free check reads what your domain publishes in DNS.
In this topic
- Abuse Desk Operations
- ESP Outbound Monitoring Systems
- Customer Vetting for ESPs
- Vetting Transactional Email Accounts