Directions
1Pick one region and stay in it
SES configuration is regional: identities, sandbox status, and sending quotas exist per region. Pick the region closest to your app (or where the rest of your stack lives) and do everything there. Verifying a domain in us-east-1 does nothing for eu-west-1.
2Create the domain identity with Easy DKIM
In the SES console open Identities, then Create identity, choose Domain, and enter your sending domain. Leave Easy DKIM on with a 2048-bit key — SES generates three CNAME records that point selectors at keys AWS rotates for you, so you never touch DKIM again after today.
Add the three CNAMEs at your DNS host. On Cloudflare set them to DNS only. The identity flips to Verified once SES sees all three, usually within minutes.
abc123._domainkey.example.com CNAME abc123.dkim.amazonses.com
def456._domainkey.example.com CNAME def456.dkim.amazonses.com
ghi789._domainkey.example.com CNAME ghi789.dkim.amazonses.com
3Set a custom MAIL FROM subdomain
By default the envelope sender is amazonses.com, which passes SPF but doesn't align with your domain — and alignment is what DMARC checks. Set a custom MAIL FROM like bounce.example.com in the identity settings, then add the MX and SPF records SES shows you.
This is the difference between technically-passing and actually-aligned mail. With MAIL FROM on your subdomain, both SPF and DKIM align and a p=reject DMARC policy is safe.
bounce.example.com MX 10 feedback-smtp.us-east-1.amazonses.com
bounce.example.com TXT v=spf1 include:amazonses.com ~all
4Wire up bounce and complaint handling
Before asking for production access, decide what happens on a bounce or complaint — AWS asks, and suspends accounts that ignore them. The lightweight setup: create an SNS topic per event type on the identity's Notifications tab and subscribe an endpoint or queue that at minimum records the address so you stop sending to it.
A bounce rate above roughly 5% or a complaint rate above 0.1% puts the account under review, so suppressing bad addresses isn't optional hygiene — it's what keeps sending enabled.
5Request production access
New SES accounts are sandboxed: you can only send to verified addresses. In the SES console open Account dashboard and request production access. Write the request like a human explaining a legitimate use: what the mail is (transactional receipts, alerts), expected daily volume, how recipients opted in, and how bounces and complaints are handled (point at step four).
Approval typically takes a day. You start with a modest quota (often 50,000/day) that rises automatically with clean sending. Send a test to a mailbox you control and read the headers: you want spf=pass, dkim=pass, and dmarc=pass with your domain, not amazonses.com, in the alignment.
Common issues & fixes
Domain stuck in 'Verification pending'.
One of the three DKIM CNAMEs is wrong — usually a doubled domain suffix or a proxied record. All three must resolve; check each with a DNS lookup before waiting longer.
Production access request denied.
Generic requests get generic denials. Resubmit with specifics: mail types, volume, opt-in source, and your bounce/complaint handling. Mentioning a working suppression flow is usually the difference.
Mail passes SPF and DKIM but fails DMARC.
Alignment, not authentication. The envelope sender is still amazonses.com — set the custom MAIL FROM subdomain and DMARC alignment follows.
Sending works in the console test but the app gets AccessDenied.
The IAM role or user lacks ses:SendEmail / ses:SendRawEmail on that identity, or the app is calling a different region than the one you configured. Match the region first; it's the more common miss.
Account under review for bounce rate.
You're sending to stale addresses with no suppression. Enable account-level suppression in SES settings, purge known-bad addresses from your lists, and reply to the review with what changed.
Honesty note: articles are drafted with AI assistance, then a human
checks each one against the vendor's current setup flow before it
publishes — nothing goes live unreviewed. Vendor interfaces still
change; if a step looks different, the underlying record is what
matters.