Sending email via AWS SES within AWS Lambda function
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
AWS Lambda and Amazon SES work well together when you need transactional email without managing a mail server. The main requirements are straightforward: SES must be configured correctly, the Lambda execution role must be allowed to send mail, and the function must call the SES API in the same region where your identity is verified.
What Must Be Ready First
Before writing code, make sure the AWS side is correct.
First, verify the sender identity in SES. Depending on your setup, this may be a single email address or an entire domain. If your account is still in the SES sandbox, you can only send to verified recipients, which surprises many first-time users.
Second, give the Lambda execution role permission to call SES. A minimal IAM policy looks like this:
Third, keep region alignment in mind. If your verified identity exists in us-east-1 but your Lambda client talks to us-west-2, the call may fail even though the code looks fine.
A Simple Lambda Example in Python
Python is a good fit here because boto3 is widely used and easy to test locally. The following handler accepts a target address and message details from the event payload.
Example test event:
This is enough for plain-text transactional mail. For HTML content, you can include an Html section in the body as well.
Handling HTML and Better Configuration
Most real applications want both text and HTML. They also usually read defaults from environment variables instead of hardcoding them into the function. Here is a slightly richer version:
If you send the same style of email often, move the subject and template rendering into a small helper layer. Lambda should stay focused on orchestration rather than hand-building long HTML strings inline.
Operational Considerations
A Lambda function that sends email usually lives behind another event source, such as:
- API Gateway for user-triggered notifications
- EventBridge for scheduled reports
- SQS for decoupled background email delivery
- SNS for fan-out workflows
This architecture matters because SES is an external side effect. If retries occur, you may accidentally send duplicate messages. For important flows, include an idempotency key in your event payload and store send state in DynamoDB or another durable store.
Logging is also important. Log the SES MessageId, recipient, and a request identifier, but do not log full email bodies if they may contain sensitive data.
Local and Cloud Testing
You can test the business logic locally, but the real API call still depends on AWS credentials and SES configuration. A small local smoke test looks like this:
In AWS, use a Lambda test event first, then inspect CloudWatch Logs for failures such as access denied, identity not verified, or sandbox restrictions.
Common Pitfalls
The most common mistake is forgetting that SES identities are regional. Verifying an address in one region does not automatically verify it everywhere.
Another frequent problem is the SES sandbox. Developers often verify the sender, deploy successfully, and then wonder why sending to a normal recipient fails. If the account is still in sandbox mode, the recipient may need verification too.
Permission errors are also common. The Lambda role needs SES send permissions, and the function needs the correct region configuration.
Finally, watch for duplicate sends during retries. Lambda is event-driven, and retries are normal. If email should be sent exactly once, design for idempotency rather than assuming a single invocation.
Summary
- SES plus Lambda is a simple serverless pattern for transactional email.
- You need a verified SES identity, correct IAM permissions, and matching AWS regions.
- A small
boto3handler can send plain-text or HTML messages with little code. - Event-driven retries can create duplicate email unless you handle idempotency.
- CloudWatch logs and the SES
MessageIdare the first things to inspect when debugging.
Related reading
- Sending html content in AWS SNSSimple Notification Service emails notifications
- Sending SMS with Amazon AWS services PHP
- Server Sent Events In a Kubernetes Cluster
- Serverless framework deployment error You're not authorized to access this resource
- Serverless Framework with AWS Lambda error Cannot find module
- Service account secret is not listed. How to fix it?
- Service discovery vs load balancing
- Service located in another namespace

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.