AWS Builder Center

I Built a Daily Email Bot with AWS Lambda: A Zero-Cost Student Project

A complete record of how I built a daily reminder email bot using AWS Lambda, EventBridge, and SES—entirely within the free tier, with the pitfalls I hit and reusable code you can copy.

Why I Wanted to Build This

As a student, I constantly forget small recurring things—weekly assignment reminders, daily vocabulary practice, or sending activity notices to club members. Doing it manually is tedious, and third-party tools usually charge money.
Since I am learning AWS anyway, I decided to build a scheduled email bot with Lambda. The goal was simple: every morning at 8 AM, automatically send me an email with customizable content.
The entire solution runs within the AWS Free Tier—not a single cent spent.

The Architecture

This project uses three AWS services:
  • Lambda: runs the code that sends the email
  • EventBridge: triggers Lambda on a schedule
  • SES (Simple Email Service): actually sends the email
The flow is straightforward: EventBridge triggers Lambda on schedule, Lambda calls SES to send the email. No servers, no complicated configuration.

Step 1: Configure SES and Verify Email Addresses

SES is in sandbox mode for new accounts, meaning you can only send emails to verified addresses. This is completely sufficient for learning.
Go to the SES console, select "Verified identities," and click "Create identity." Enter your email address, and SES will send a verification email. Click the link in the email, and verification is complete.
Pitfall alert: if you use a school email, you might not receive the verification email, or it might land in spam. I tried my school email twice with no luck, then switched to Gmail and it verified immediately.
You also need to verify the sender email. To keep things simple, I set both the sender and recipient to the same Gmail address.

Step 2: Create the Lambda Function

Go to the Lambda console, click "Create function," and choose "Author from scratch."
  • Function name: daily-email-bot
  • Runtime: Python 3.12
  • Architecture: x86_64 (default is fine)
Once created, paste the following code into Lambda's built-in editor:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import boto3
from botocore.exceptions import ClientError

def lambda_handler(event, context):
ses = boto3.client('ses', region_name='ap-northeast-1')

sender = "your-email@gmail.com"
recipient = "your-email@gmail.com"

subject = "Daily Reminder"
body = "Don't forget to practice your vocabulary today!"

try:
response = ses.send_email(
Source=sender,
Destination={'ToAddresses': [recipient]},
Message={
'Subject': {'Data': subject, 'Charset': 'UTF-8'},
'Body': {'Text': {'Data': body, 'Charset': 'UTF-8'}}
}
)
return {"statusCode": 200, "body": "Email sent successfully"}
except ClientError as e:
return {"statusCode": 500, "body": str(e)}
Note: replace your-email@gmail.com with your verified email, and change region_name to the region where your SES is located.

Step 3: Grant Lambda Permission to Use SES

By default, Lambda has no permission to send emails. You need to give it an IAM role.
In the Lambda function's "Configuration" tab, find "Permissions" and click the execution role name to enter the IAM console. Add the following inline policy:
1
2
3
4
5
6
7
8
9
10
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ses:SendEmail",
"Resource": "*"
}
]
}
After saving, Lambda has permission to call SES.

Step 4: Set Up Scheduled Trigger with EventBridge
Back in the Lambda console, click "Add trigger" and select EventBridge (CloudWatch Events).

  • Rule: create a new rule
  • Rule name: daily-email-trigger
  • Rule type: Schedule expression
  • Schedule expression: cron(0 8 * * ? *)
This expression means trigger every day at 8:00 UTC. If you are in Hong Kong (UTC+8), the actual trigger time is 4 PM local time. To make it 8 AM local time, use cron(0 0 * * ? *) (UTC 0:00 = Hong Kong 8:00).
Pitfall alert: EventBridge's cron expression is not the same as Linux cron. It does not support writing the year directly, and the field order is "minute hour day month weekday year." I initially wrote it in Linux format and nothing triggered—only after checking the docs did I realize the difference.
After saving, the trigger is active.

Step 5: Test and Verify
In the Lambda console, click "Test," create an empty event {}, and run it. If configured correctly, you will receive an email within seconds.

If you do not receive it, check the following:
  • Are both sender and recipient emails verified in SES?
  • Does the Lambda execution role have ses:SendEmail permission?
  • Are the regions consistent? (SES and Lambda must be in the same region)
  • Is the email landing in spam?
I initially forgot to grant Lambda SES permission, and the test returned AccessDenied. After adding the policy, it worked.

Cost Breakdown
This project stays entirely within the free tier:

  • Lambda: 1 million free requests per month; I only invoke it once per day
  • EventBridge: 14 million free events per month; I only use 1 per day
  • SES: 62,000 free emails per month (when sent from EC2 or Lambda); I only send 1 per day
  • In other words, this bot can run for a year at zero cost.
A Few Things I Learned
First, Lambda's permission model is critical. Every function needs an execution role, and the role determines which services it can access. This is the core of AWS security design, and the easiest thing for beginners to overlook.
Second, SES sandbox mode has pitfalls. New accounts can only send to verified emails. To send to anyone, you need to request production access. For learning purposes, verifying your own email is enough.
Third, EventBridge cron expressions need separate study. They are not exactly the same as Linux cron, especially regarding time zones—AWS defaults to UTC, so you must convert to local time.
Fourth, this architecture can be extended. Right now I only send fixed content, but I could have Lambda read content from DynamoDB, or send different reminders based on the date. I could even add API Gateway to make it a manually triggerable endpoint.

What I Plan to Do Next
This bot now sends me an email on time every day and runs stably. Next, I want to:

  • Store reminder content in DynamoDB for dynamic content
  • Add an API Gateway endpoint so I can manually trigger or modify reminders
  • Try sending HTML-formatted emails with SES for a nicer look
  • Manage the whole project with AWS SAM for easier deployment and version control
For Students Who Want to Try This Too
If you want to build something practical with AWS, the Lambda + EventBridge + SES combination is well worth trying. It is simple, free, solves a real problem, and lets you understand three core services at once.
Most importantly, when you receive that email from your own bot every morning, you will truly feel the practical value of cloud computing.
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article