Bounces and complaints
How SES feedback reaches the suppression list, and what each kind of bounce does.
Every email Base316 sends on a customer's behalf is recorded as a delivery and checked against the environment's suppression list first. SES reports what happened to each message afterwards — delivered, delayed, bounced, or marked as spam — through an SNS topic that posts to the API:
SES configuration set → SNS topic → POST /internal/ses/notificationsSetting that up in AWS is docs/runbooks/ses-feedback.md in the repository.
What each event does
| SES event | Delivery status | Suppresses? |
|---|---|---|
Delivery | Delivered | No |
DeliveryDelay | Delayed | No — SES is still retrying |
Bounce, Permanent | Bounced | Yes, as HARD_BOUNCE |
Bounce, Transient | Bounced | Only the third in seven days, as SOFT_BOUNCE |
Complaint | Marked as spam | Yes, as COMPLAINT |
- A transient bounce is not a dead address. A full mailbox empties and a
server that deferred comes back, so one soft bounce is recorded on the
delivery and nothing else. Three to the same address, in the same
environment, within seven days suppress it: at that point it is behaving
like a dead address, and mailing it keeps hurting the sender's reputation.
Bounces about the message rather than the mailbox (
ContentRejected,AttachmentRejected) never count. - An
Undeterminedbounce counts like a transient one. - A complaint whose feedback type is
not-spamis recorded and does not suppress — it is a report that the recipient said the opposite. - A status never moves backwards: a
Deliverythat arrives after a complaint leaves the message marked as spam.
The delivery keeps what SES said — bounce type, sub-type and the receiving
server's diagnostic (smtp; 550 5.1.1 user unknown) — and the suppression's
note carries the same, so Settings → Email answers "why are we not
mailing this person" without a log search.
Whose list
A bounce or complaint suppresses the address in the environment that sent the message, and nowhere else. The environment comes from the delivery row that SES's message id points to — never from the notification — and only that delivery's own recipient can be suppressed.
One exception: a complaint about mail sent from Base316's shared sender — an environment that has not verified a sending domain — is also suppressed platform-wide. That complaint counts against the shared domain for every customer using it, so no environment can mail that person from it again. Mail from a customer's own verified domain stays environment-scoped: that reputation is theirs. A send refused this way is recorded as Suppressed, with a note saying why; verifying a sending domain lets that environment mail the address from its own.
Unsuppressing an address (Unsuppress on the list, which needs the organization-manage permission) only removes the environment's own entry.
Trust
The endpoint is unauthenticated — SNS presents no API key — so every message has to earn its way in:
- The
TopicArnmust be one ofBASE316_SES_SNS_TOPIC_ARNS. Anyone can create an SNS topic and subscribe our URL to it, and AWS would sign those messages too; the allow-list is what makes a signed message ours. Unset, the endpoint answers503. - The SNS signature must verify (SignatureVersion 1 or 2). The signing
certificate is downloaded only over HTTPS from an
sns.<region>.amazonaws.comhost, with redirects refused, and cached for a day. - A
SubscriptionConfirmationis confirmed by visiting itsSubscribeURL— only when the topic is allow-listed, and only if that URL is also an SNS host. - Each notification is claimed by its SNS
MessageIdbefore it is acted on (sns_message), so SNS's at-least-once redelivery cannot apply it twice. A notification whose processing failed answers500and is let through again on the retry.
A notification naming an SES message id with no delivery row — Base316's own
account mail, or another product sending from the same SES account — is
acknowledged with 200 and ignored, so SNS stops retrying it.
Processed claims are kept for 30 days and pruned daily by prune-sns-messages;
failed ones are kept.

