
Editorial date: . First published October 19, 2026.
SES bounces, complaints, and suppressions are a feedback loop
Bounce and complaint events should change future sending, not just update a chart. Here is the state model behind an SES feedback pipeline, including authentication, correlation, suppression scope, and uncertain outcomes.
A bounce and a complaint answer different questions
A bounce says delivery failed. A complaint says a recipient or receiving system reported the message as unwanted through a feedback mechanism. The response to both can include preventing future sends, but they aren’t interchangeable evidence.
AWS’s deliverability guide distinguishes hard bounces from soft bounces. A hard bounce is persistent failure, such as a nonexistent mailbox. A soft bounce is temporary, such as a full mailbox or a connection problem. SES retries temporary failures and reports them when it stops retrying; an application shouldn’t submit a fresh copy just because delivery hasn’t completed yet.
A complaint may arrive after the receiving server accepted a message. That doesn’t contradict a delivery event. The server accepted it, and a recipient later objected. Treating “delivered” as an irreversible happy ending loses that distinction.
Neither event is an inbox-placement measurement. Absence of a bounce doesn’t mean the message appeared in the inbox, and absence of a complaint doesn’t mean nobody clicked Spam.
Provider suppression is useful, but it’s not your whole policy
The SES account-level suppression list applies to an AWS account in the current region. Its configured reasons control whether SES suppresses a listed destination. AWS documents that a suppressed send can be accepted without an actual delivery attempt, and still counts toward the daily sending quota.
That behavior alone is enough reason not to equate API success with delivery. It also explains why applications benefit from checking known recipient policy before spending a send attempt.
As of October 2026, the same AWS guide describes configuration-set overrides and tenant-level suppression options. Inspect effective configuration rather than assuming every send follows one account-wide default. An override can materially change what a “suppressed destination” means for that message.
An application’s policy has additional concerns: unsubscribe preferences, consent records, domain-specific restrictions, and the explanation shown to an operator. Provider suppression doesn’t manage all those business relationships for you.
Keep the records distinct. “Hard bounce from SES,” “complaint,” and “unsubscribed from product updates” should not collapse into one unexplained boolean. Different causes require different review procedures, and an unsubscribe from one optional stream doesn’t automatically prohibit every legitimate account-security notice.
That stream-specific preference distinction does not clear a hard-bounce or complaint restriction, or override applicable consent requirements. A security-related subject line isn’t a suppression bypass.
Authenticate first, then identify the attempt
A feedback endpoint changes sending permissions. Treat it accordingly.
AWS requires SNS signature verification before processing notifications and subscription confirmations. Validate the expected topic and the signing certificate source as well. A JSON object with an AWS-looking field name isn’t an authenticated provider event.
After authentication, correlate the provider message identifier and region to a durable application attempt. Check the original sender and affected recipient. Don’t let an arbitrary domain ID in an HTTP query or an event’s unrelated metadata choose whose records to mutate.
For messages with several recipients, apply recipient-specific evidence to the affected recipients. A bounce for one destination is not proof that every address on the original message failed. Your storage model needs enough recipient detail to avoid punishing the wrong person.
There is also a timing race: feedback can reach your service before the provider response has finished being persisted. Design for that case. A valid event that can’t yet be correlated should have a durable retry or reconciliation path, rather than receiving a successful acknowledgement and disappearing.
Store an event once; apply its meaning once
Notifications can repeat. AWS explicitly notes that using several notification mechanisms can yield duplicates. Your system should also tolerate transport-level redelivery without inventing a new user complaint each time.
Use an event identity and a durable processing boundary. Acknowledge only after the state change is safe. If processing fails halfway through, the next attempt should be able to finish rather than finding an “already processed” marker written before the actual work.
Separate two kinds of state: the historical event stream and the current decision. The event history can truthfully contain Delivery followed by Complaint. The current outcome should not switch back to Delivered merely because a duplicate or delayed delivery notification arrives afterward.
Illustrative history versus current policy
The following is a design example, not a real event log. Assume your application suppresses a recipient and holds its sender when it receives an authentic, matching complaint. The identifiers below label evidence; they aren’t a proposed SES payload schema.
| Observation | Historical evidence retained | Current decision |
|---|---|---|
| Delivery D1 matches attempt A | Receiving server accepted A | Delivery recorded; no inbox-placement inference |
| Complaint C1 matches A and its recipient | Both D1 and C1 | Recipient suppressed; sender held for review |
| D1 is delivered to the handler again | Same delivery fact, not another business send | Complaint outcome and restrictions remain |
| C1 is delivered again | Same complaint fact | No second hold action or duplicate review task |
An operator should be able to answer two separate queries: “What happened to A?” and “May this recipient receive another message now?” Last-write-wins storage cannot reliably answer both. Keep an event deduplication identity distinct from the logical send identity; one message can legitimately have several different events.
If an event arrives before A can be correlated, retain it for retry or return a retryable failure. Don’t mark it processed until its intended durable changes are safe. A later reconciliation must check the original sender and affected recipient, not infer ownership from whichever account is currently asking about the event.
Check suppression at the dispatch boundary
A suppression check is most useful as close as possible to the actual send decision. Filtering a campaign list when it is first assembled isn’t enough if the batch sits in a queue while new complaints arrive.
For an application service, recheck recipient policy when reserving the attempt. Keep that check coordinated with quota reservation, credential validity, domain state, and the current send permission. Otherwise a request can pass one stale check while another request changes the relevant state.
No design eliminates every race with an external recipient server. The practical objective is narrower: once your system durably knows that a recipient must not receive another message, ordinary dispatch must consult that fact. A queue worker isn’t exempt because it started earlier.
Store enough reason data to explain a refusal without exposing other customers’ activity. If your service has a cross-domain safety policy, a sender may need to know that dispatch is blocked without receiving another tenant’s message history or complaint details.
Test the behavior, not merely event ingestion
The SES mailbox simulator can generate success, bounce, complaint, and suppression scenarios. A useful test runs through the same sending and event paths as application traffic.
For a bounce scenario, verify the original attempt is identified, the appropriate recipient is restricted, and a later request is refused according to policy. For a complaint, verify the adverse outcome remains visible even if a delivery notification is processed afterward. Repeat the event to check deduplication.
Mind the simulator’s limitations. AWS says its bounce address is not added to the SES suppression list. Simulator mail is billable and remains subject to the account’s sending rate, though it doesn’t consume the daily sending quota or affect reputation metrics. Your application may still account for the attempt under its own rules.
Also test the unglamorous cases without sending more mail: invalid signatures, foreign topics, unrelated provider IDs, mismatched recipients, and a temporary storage failure. These refusal and retry cases are where a feedback handler becomes a trustworthy control instead of a public write endpoint.
Restoring an address is a review, not a retry button
Removing a suppression should require evidence that addresses the original reason. A corrected typo can justify a new address. A recipient who complained needs more than the sender saying the next email is important. An unsubscribe requires a real preference change, not a transport workaround.
Be explicit about scope. Clearing an application record doesn’t necessarily clear SES suppression, and clearing SES doesn’t necessarily restore application permission. Keep a review trail showing the reason, actor, time, and affected scope. Don’t silently clear restrictions during imports, provider migrations, DNS verification, or subscription upgrades.
Complaint coverage is incomplete. AWS specifically states that Gmail doesn’t provide complaint data to SES. A quiet complaint dashboard is not proof of universal satisfaction. Consent, frequency, unsubscribe behavior, and content remain necessary controls even with a healthy feedback pipeline.
The managed boundary and the DIY boundary
SendHog, which we build, implements signed provider feedback, attempt correlation, permanent-bounce and complaint suppression, and complaint-triggered sending holds. Manual and abuse disables persist independently of DNS rechecks. For the public interface, the sending guide defines message outcomes and explains that delivery does not mean inbox placement; the API reference specifies domain-scoped keys and the read permission needed to inspect saved messages. These documents describe customer-visible behavior, not a public audit of the internal event processor.
That’s an implementation choice, not a claim that every SES event is exposed as a customer webhook or that every mailbox provider reports complaints. Direct SES with your own durable event processor is a sound alternative when you want to own this policy. Another ESP may provide the specific retention, event tooling, or support workflow you need.
For the broader readiness checklist, see SES production setup. For the product rationale behind treating this loop as part of sending rather than optional analytics, see why we built SendHog.
The invariant to preserve is simple: authentic adverse feedback must influence future sends, and the system must be able to explain why. If that remains true during duplicate events, retries, migrations, and operator reviews, the feedback pipeline is doing its job.
Primary sources reviewed October 19, 2026. Provider capabilities and pricing can change.