Case Studies · Last updated June 2026
Case Study: Fixing Email Spoofing and Deliverability with AWS SES, DKIM, and DMARC
Results at a Glance
- DKIM, DMARC, and SPF deployed across multiple client production domains via AWS SES
- Spoofing vulnerabilities resolved — unauthenticated mail rejected by receiving servers
- Bounce-rate monitoring and suppression-list hygiene kept accounts safely under AWS's 5% bounce / 0.1% complaint thresholds
- Operational runbook adopted for handling hard bounces, soft bounces, and suppression events
The Problem
Across the client domains I manage, mail could be spoofed: none of them had DKIM, DMARC, or SPF records, so receiving servers had no way to verify that a message claiming to come from one of these domains actually did. On top of that, bounces went unhandled, silently eroding sender reputation while the bounce rate crept toward AWS's 5% cutoff.
All of these domains send through AWS Simple Email Service (SES), and SES tracks each account's bounce rate. Let it climb too high and AWS throttles or suspends sending, usually before anyone notices a problem from the user side. So bounce handling had to be fixed alongside the authentication.
The Fix, Part 1: Email Authentication
I implemented production email authentication via AWS SES across each client domain: SPF records authorizing SES sending infrastructure, DKIM signing through SES's Easy DKIM (CNAME records published per domain), and a DMARC policy that tells receiving servers to reject unauthenticated mail claiming to come from our domains. This closed the spoofing hole: attackers can no longer impersonate client domains to customers, and authenticated mail builds positive reputation with ISPs.
The Fix, Part 2: Understanding SES Bounce Types
Authentication was only half of the work. Bounce handling needed just as much attention:
- Sender reputation: ISPs monitor your bounce frequency. A high bounce rate signals spam, and your emails get blocked or land in spam folders.
- AWS account health: SES tracks your bounce rate. Exceed the threshold — normally 5% for bounces and 0.1% for complaints — and AWS may put your account under review or pause sending.
- Cost efficiency: sending to addresses that will never receive your emails wastes API calls.
- User experience: bounce handling surfaces data-quality problems and keeps mailing lists clean.
Hard bounces (permanent failures)
A hard bounce means the email can never be delivered — the recipient's server explicitly rejected it, and retrying won't help. Common causes: the address doesn't exist, the domain has no mail server, or your sender is permanently blocked. SES subtypes: General, NoEmail, Suppressed, and OnAccountSuppressionList.
{
"notificationType": "Bounce",
"bounce": {
"bounceType": "Permanent",
"bounceSubType": "General",
"bouncedRecipients": [{
"emailAddress": "[email protected]",
"action": "failed",
"status": "5.1.1",
"diagnosticCode": "smtp; 550 5.1.1 user unknown"
}],
"timestamp": "2026-02-18T10:30:00.000Z"
}
}Soft bounces (transient failures)
Soft bounces are temporary: the recipient's server is reachable but delivery is delayed — mailbox full, server temporarily unavailable, message too large, or a transient DNS failure. Subtypes include MailboxFull, MessageTooLarge, ContentRejected, and AttachmentRejected. Handle these with retry logic and exponential back-off.
{
"notificationType": "Bounce",
"bounce": {
"bounceType": "Transient",
"bounceSubType": "MailboxFull",
"bouncedRecipients": [{
"emailAddress": "[email protected]",
"action": "failed",
"status": "4.2.2",
"diagnosticCode": "smtp; 452 4.2.2 Mailbox full"
}],
"timestamp": "2026-02-18T10:45:00.000Z"
}
}Suppression-list bounces
SES automatically maintains a suppression list to protect your reputation: any address that hard-bounces or complains gets added, and further sends to it are stopped before they even leave SES — reported as OnAccountSuppressionList.
Reading bounce status codes
The status field uses SMTP codes: 5.x.x = permanent (5.1.1 bad mailbox, 5.1.2 bad domain, 5.2.1 mailbox disabled, 5.7.1 delivery not authorized) and 4.x.x = temporary (4.2.2 mailbox full, 4.4.1 connection timeout, 4.7.1 temporary policy reason).
Operating the Suppression List
Check whether an address is suppressed, and why:
aws sesv2 get-suppressed-destination \
--email-address "[email protected]" \
--region ap-northeast-1The response tells you the reason (BOUNCE or COMPLAINT), when it was added, and which message caused it. List suppressed addresses (optionally filtered by reason and date range):
aws sesv2 list-suppressed-destinations \
--region ap-northeast-1 \
--reasons BOUNCE \
--start-date 2025-01-01T00:00:00Z \
--end-date 2026-01-31T23:59:59ZRemove an address only after confirming it's valid again:
aws sesv2 delete-suppressed-destination \
--email-address "[email protected]" \
--region ap-northeast-1And make sure account-level suppression covers both bounces and complaints in production:
aws sesv2 put-account-suppression-attributes \
--region ap-northeast-1 \
--suppressed-reasons BOUNCE COMPLAINTKey Takeaways
Hard bounces are permanent, so those addresses come off the list immediately; soft bounces get retried with exponential back-off. The number worth watching is the account bounce rate, since AWS starts penalizing above 5%, and validating addresses before sending stops most bad data from ever turning into a bounce. Authentication (DKIM, DMARC, SPF) and bounce handling only fixed deliverability here once both were in place.
Email deliverability problems in production?
I set up SES authentication, bounce handling, and monitoring for client domains.
See Services