Amazon SES
Managed email sending — transactional and bulk mail from your application, no SMTP servers to run. Here's what SES is good for, what it costs, how it connects to the rest of your AWS architecture, and the mistakes Design Beaver catches as you draw.
What SES is
SES (Simple Email Service) sends email on your behalf. Instead of running SMTP servers and fighting deliverability, your application calls the SES API — or an SES SMTP endpoint — and SES handles the sending, DKIM signing, and bounce/complaint tracking. It’s built for the mail a system sends programmatically: password resets, receipts, alerts, and bulk/marketing sends. You can only send from identities you’ve verified, and a new account starts in a sandbox with tight limits until you request production access.
Design Beaver models SES as a regional, API-accessed service rather than something that sits inside a VPC subnet, and validates as you draw which services can use it and how each connection has to be set up to be correct.
When to use SES (and when not to)
Reach for SES when your application needs to send email and you don’t want to run or manage SMTP servers. It’s the right tool when you want AWS-native sending with deliverability features like DKIM and dedicated IPs, plus built-in bounce and complaint handling.
Don’t reach for it when you need in-app or push notifications rather than email — that’s SNS or a push service, not SES. It’s also the wrong tool when you need a full inbox/mailbox product for end users. SES sends and receives mail programmatically; it is not a hosted mailbox like WorkMail.
Variants: how you send
SES gives you two ways to hand it a message. The API is the usual choice for code that already has AWS credentials; the SMTP interface is for apps or frameworks that already speak SMTP.
| Option | What it is |
|---|---|
| SES APIdefault | Call SendEmail/SendRawEmail through the AWS SDK — the usual choice for application code already using AWS credentials. |
| SMTP interface | Send through SES's SMTP endpoint with SMTP credentials — for existing apps or frameworks that already speak SMTP. Maps to ses:SendRawEmail under the hood. |
SES pricing
You pay per message — each send is a charge, and each receive is a charge too — plus a per-GB charge on outgoing message data and optional features like dedicated IPs. Outgoing data isn’t free-tier eligible.
Billed per message charge — each email sent is one charge, and each email received is one charge too (some features like Virtual Deliverability Manager add extra charges per message). On top of that you pay per GB of outgoing attachment data, plus optional features (dedicated IPs). Outgoing data is not free-tier eligible.
| Option | Representative rate |
|---|---|
| api | on the order of $0.10 per 1,000 emails sent, plus $0.12 per GB of attachment data (data charge confirmed; per-email rate approximate) |
Free tier
- 3,000 message charges per month for the first 12 months after first use (covers sends and receives combined)
Keeping the bill down
- Batch and template messages rather than sending many near-identical individual emails
- Keep bounce/complaint rates low to preserve sending reputation and avoid throttling
us-east-1 (rates vary by region). Rates as of 2026-07. Verify at the official pricing page before using for real cost estimates — this list is not kept in sync with AWS pricing changes.
How SES connects to other services
SES is mostly a sink: compute sends to it. A Lambda or an app on EC2 calls SES to send mail, and the sender’s execution role or instance profile carries the ses:SendEmail permission — so those edges live on the sender’s side, not on SES. What SES itself originates are the receiving-side actions: its receipt rules connect out to store or process inbound mail, and it publishes bounce and complaint notifications. Each of those edges has a specific requirement, and Design Beaver models them so it knows what belongs on the connection.
SES email receiving: a receipt rule's 'deliver to S3' action stores an inbound message in an S3 bucket for the application to pick up
SES email receiving: a receipt rule's 'invoke Lambda' action calls a function to process an inbound message (invoked synchronously when it controls mail flow)
SES publishes bounce, complaint, and delivery notifications to an SNS topic (via a configuration set or the identity's notification settings) so the application can react to failed or flagged sends
What SES can’t connect to
Some edges look reasonable on a canvas but aren’t real AWS integrations — SES is an email API, not a database or an HTTP origin. Design Beaver flags them instead of letting you draw a diagram that can’t be built.
SES sends email through its API; it has no database client relationship with RDS. An application queries the database and then calls SES — the two never connect directly.
No direct integration — SES doesn't read or write a database. Application code (on Lambda or EC2) talks to DynamoDB and separately calls SES.
SES is an email-sending API, not an HTTP content origin — CloudFront caches web content from origins like S3 or ALB, never an email service.
Route 53 hosts the DNS records that make a domain send-ready for SES (DKIM, SPF, MX for receiving), but that's DNS configuration for a verified identity, not an architectural connection from SES to Route 53.
Anti-patterns Design Beaver catches
These are the SES mistakes that pass a diagram review but break in production — the ones the validation engine flags as you draw.
Building an email flow assuming full sending capacity while the account is still in the SES sandbox
Why it breaksA new SES account can only send to verified addresses and has low daily quotas until production access is granted — code that works in testing silently fails to reach real recipients
Do this insteadRequest production access early, and verify the sending domain/address regardless of sandbox status
Sending email inline in a user-facing request path with no queue in front
Why it breaksSES latency or throttling then shows up as slow or failed API responses to the user, and a send failure can fail the whole request
Do this insteadEnqueue the send (SQS) and have a worker call SES asynchronously, so the user request returns immediately and sends retry independently
Ignoring bounces and complaints
Why it breaksHigh bounce/complaint rates hurt sender reputation and can get sending paused — and you have no visibility into failed deliveries
Do this insteadRoute bounce/complaint notifications (via a configuration set) to a queue or function and prune bad addresses
Gotchas that bite in production
- The sandbox will surprise you. Until you request production access, a new account can only send to verified addresses and has low daily quotas. Code that works in testing silently fails to reach real recipients — request production access early.
- You must verify the sending identity. SES won’t send from a domain or address you haven’t verified, sandbox or not.
- Sending inline blocks the user. If you call SES in a user-facing request path with no queue in front, its latency or throttling becomes slow or failed API responses — and a send failure can fail the whole request. Enqueue the send on SQS and let a worker call SES asynchronously.
- Bounces and complaints are your problem. High rates hurt sender reputation and can get sending paused, and you have no visibility into failed deliveries. Route bounce/complaint notifications through a configuration set to a queue or function you act on, and prune bad addresses.
Further reading
Frequently asked questions
When should you use Amazon SES?
How much does Amazon SES cost?
Can Amazon SES write to an S3 bucket?
Does Amazon SES connect to a database like RDS or DynamoDB?
Why do my SES emails work in testing but not reach real recipients?
Validate your SES architecture as you draw
Design Beaver checks your AWS design in real time — missing queues, invalid connections, and security anti-patterns, caught before you ship. It’s live in beta, free, and runs in your browser with no account.
Open the app →Prefer email? Get new features in your inbox: