AWS SES bounce and complaint handling with SNS — the right way
AWS SES gives you production access and then watches your bounce and complaint rates like a hawk. If either metric crosses the threshold, your sending gets paused. The fix is wiring up Amazon SNS so you process these events in real time.
The two numbers that matter
| Metric | Best practice | AWS warning | AWS pause risk |
|---|---|---|---|
| Bounce rate | < 0.5% | 5% | ~10% |
| Complaint rate | < 0.05% | 0.08% | ~0.1% |
Bounce types explained
| Type | Subtype | Cause | Action |
|---|---|---|---|
| Permanent (hard) | General | Address does not exist | Suppress immediately, never retry |
| Permanent (hard) | NoEmail | Domain exists, no mailbox | Suppress immediately |
| Permanent (hard) | Suppressed | SES account-level suppression | Already suppressed |
| Transient (soft) | MailboxFull | Recipient mailbox is full | Retry after 7 days, suppress after 3 soft bounces |
| Transient (soft) | MessageTooLarge | Email exceeds size limit | Reduce email size/attachments |
| Transient (soft) | ContentRejected | Server rejected content | Check for spam trigger words |
| Undetermined | Undetermined | Unknown reason | Retry once, then suppress |
Setting up SNS topic for bounce/complaint notifications
Step 1: Create an SNS topic in the AWS console. Name it ses-notifications. Copy the ARN.
Step 2: In SES Console → Configuration → Configuration Sets → your config set → Event destinations → Add destination. Select SNS. Check Bounces and Complaints.
Step 3: Subscribe an HTTPS endpoint to the SNS topic. SES Mailbox provides this endpoint automatically once you connect your AWS credentials.
# Example SNS bounce notification payload
{
"notificationType": "Bounce",
"bounce": {
"bounceType": "Permanent",
"bounceSubType": "General",
"bouncedRecipients": [{
"emailAddress": "user@nonexistent.com",
"action": "failed",
"status": "5.1.1",
"diagnosticCode": "550 5.1.1 The email account does not exist."
}],
"timestamp": "2026-05-04T09:12:33.000Z",
"feedbackId": "0102abc..."
},
"mail": {
"source": "newsletter@yourdomain.com",
"destination": ["user@nonexistent.com"],
"messageId": "0102abc..."
}
}Webhook handler example (Node.js)
// Express.js endpoint to process SES SNS notifications
app.post('/webhooks/ses', express.json(), async (req, res) => {
const message = JSON.parse(req.body.Message);
if (message.notificationType === 'Bounce') {
const bounce = message.bounce;
for (const recipient of bounce.bouncedRecipients) {
if (bounce.bounceType === 'Permanent') {
await db.suppressions.upsert({
email: recipient.emailAddress,
reason: 'HARD_BOUNCE',
timestamp: bounce.timestamp,
});
}
}
}
if (message.notificationType === 'Complaint') {
for (const recipient of message.complaint.complainedRecipients) {
await db.suppressions.upsert({
email: recipient.emailAddress,
reason: 'COMPLAINT',
timestamp: message.complaint.timestamp,
});
}
}
res.status(200).send('OK');
});Complaint rate thresholds by ISP
| ISP | FBL available | Complaint threshold | Notes |
|---|---|---|---|
| Gmail | Aggregate only (Postmaster Tools) | < 0.10% | Above 0.3% = severe impact on inbox placement |
| Outlook / Hotmail | Yes (SNDS + JMRP) | < 0.08% | Also checks Smart Network Data Services reputation |
| Yahoo / AOL | Yes (CFL program) | < 0.10% | Individual complaints forwarded in real time |
| Apple Mail | Limited | < 0.10% | MPP affects open tracking; focus on clicks instead |
| AWS SES (platform) | Via SNS | < 0.08% warning | Pause risk at ~0.1%, AWS enforces independently |
What to do if you're already over the threshold
- Stop sending immediately
- Identify the campaign or segment that caused the spike in SES Mailbox analytics
- Run a full suppression of all hard bounces and complaints
- Reply to AWS Trust & Safety with your root cause analysis and remediation plan
- Restart only with your most-engaged subscribers (opened in last 30 days)
- Monitor daily for 2 weeks before returning to full volume
Frequently asked questions
What is the maximum bounce rate allowed by AWS SES? +
AWS warns you at 5% and can pause sending at around 10%, but these are the danger thresholds — not targets. Industry best practice is under 2%. A healthy, well-maintained list should see under 0.5% on any given send. If you are above 2%, pause and clean your list before the next send.
What is the difference between a hard bounce and a soft bounce in SES? +
A hard bounce (bounceType: Permanent) means the address is permanently undeliverable — the mailbox does not exist, or the receiving server explicitly rejected delivery with a 5xx error. Never send to a hard bounce again. A soft bounce (bounceType: Transient) means temporary failure — full mailbox, server down, rate limiting. SES retries soft bounces automatically for up to 72 hours.
Does Gmail send feedback loop (FBL) complaint notifications to SES? +
Gmail does not send individual FBL reports. They only share aggregate domain reputation data through Google Postmaster Tools. Outlook, Yahoo, and most other providers do send FBL reports via SNS. This means your actual complaint rate from Gmail users is invisible at the individual level — only your overall Postmaster Tools domain health score reflects it.
How do I set up SES to automatically suppress bounces and complaints? +
In the SES console, go to Account dashboard → Suppression list settings and enable suppression for both bounces and complaints. This is the account-level suppression list. Additionally, configure SNS notifications on your Configuration Set so that bounce and complaint events fire webhooks to your application or to SES Mailbox for real-time processing.
What should I do if my complaint rate suddenly spikes? +
Stop sending immediately. Identify which campaign or segment caused the spike by looking at per-campaign complaint data in SES Mailbox. Suppress all complainers. Check your recent sends for: missing unsubscribe links, misleading subject lines, sending to cold or inactive segments, or a deliverability partner issue. Only resume sending to your most engaged segment after the spike resolves.
How do I check my current bounce and complaint rates in AWS SES? +
In the SES console: Account dashboard → Sending statistics. You will see your 24-hour sending quota, max send rate, and rolling bounce and complaint rates. SES Mailbox also surfaces per-campaign bounce and complaint rates in the campaign analytics view, and sends alerts when your account-level rates approach the warning thresholds.
