Lab Overview
PREREQ: Complete Lab 01 before this lab. You need an existing S3 website to add the form to.
Build a working contact form that emails submissions directly to your inbox. The entire backend runs serverlessly — no web server, no database, no monthly idle cost. Lambda runs only when someone submits the form.
| Service | Purpose | Free Tier |
|---|---|---|
| Amazon SES | Sends email when the form is submitted | 62,000 emails/mo free |
| AWS Lambda | Runs your Python code to process the form submission | 1M requests/mo free |
| Amazon API Gateway | Creates the HTTPS endpoint the form posts to | 1M calls/mo free |
| AWS IAM | Role granting Lambda permission to send via SES | Always free |
Step-by-Step Instructions
1
Amazon SES
Verify Your Email Address
SES requires you to verify an email address before you can send from it in sandbox mode.
- Search for
SES(Simple Email Service) and click it - In the left sidebar click Verified identities
- Click Create identity
- Identity type: Email address
- Enter your email address and click Create identity
- Open your inbox and click the verification link from AWS
- Return to SES — status should now show Verified
2
AWS IAM
Create the Lambda Execution Role
- Search for
IAMand click it - Left sidebar → Roles → Create role
- Trusted entity: AWS service → Use case: Lambda → Next
- Search for and attach
AmazonSESFullAccess - Search for and attach
AWSLambdaBasicExecutionRole - Role name:
LambdaSESRole→ Create role
3
AWS Lambda
Create the Lambda Function
- Search for
Lambdaand click it - Click Create function → Author from scratch
- Function name:
ContactFormHandler - Runtime: Python 3.12
- Execution role: Use an existing role → select
LambdaSESRole - Click Create function
- Delete all existing code and paste the code below
- Replace both email addresses with your verified SES email
- Click Deploy
import json
import boto3
ses = boto3.client('ses', region_name='us-east-1')
SENDER_EMAIL = 'your-verified@email.com' # replace
RECIPIENT_EMAIL = 'your-verified@email.com' # replace
def lambda_handler(event, context):
try:
body = json.loads(event.get('body', '{}'))
name = body.get('name', 'Unknown')
email = body.get('email', 'Unknown')
message = body.get('message', 'No message')
ses.send_email(
Source=SENDER_EMAIL,
Destination={'ToAddresses': [RECIPIENT_EMAIL]},
Message={
'Subject': {'Data': f'New contact from {name}'},
'Body': {'Text': {'Data':
f'Name: {name}\\nEmail: {email}\\nMessage: {message}'
}}
}
)
return {
'statusCode': 200,
'headers': {'Access-Control-Allow-Origin': '*'},
'body': json.dumps({'message': 'Email sent!'})
}
except Exception as e:
return {
'statusCode': 500,
'headers': {'Access-Control-Allow-Origin': '*'},
'body': json.dumps({'error': str(e)})
}4
Amazon API Gateway
Create the API Endpoint
- Search for
API Gatewayand click it - Click Create API → HTTP API → Build
- Add integration → Lambda → select
ContactFormHandler - API name:
ContactFormAPI→ Next - Method: POST → Resource path:
/contact→ Next - Stage name:
prod→ Next → Create - Copy the Invoke URL (shown on the summary page)
- Go to CORS in the sidebar → Allow-Origin:
*→ Allow-Methods:POST, OPTIONS→ Save
5
Amazon S3
Add the Contact Form to Your Website
Create a contact.html file and upload it to your S3 bucket. Replace YOUR_API_URL with your Invoke URL from Step 4.
<!DOCTYPE html>
<html><head><meta charset="UTF-8"/><title>Contact</title></head>
<body>
<h1>Contact Us</h1>
<label>Name</label>
<input type="text" id="name"/>
<label>Email</label>
<input type="email" id="email"/>
<label>Message</label>
<textarea id="msg"></textarea>
<button onclick="send()">Send</button>
<p id="status"></p>
<script>
const API = 'YOUR_API_URL/contact';
async function send() {
const r = await fetch(API, { method:'POST',
headers:{'Content-Type':'application/json'},
body: JSON.stringify({
name: document.getElementById('name').value,
email: document.getElementById('email').value,
message: document.getElementById('msg').value
})
});
const d = await r.json();
document.getElementById('status').textContent = d.message || d.error;
}
</script>
</body></html>6
Web Browser
Test the Contact Form
- Open your S3 website and navigate to
contact.html - Fill in your name, your verified SES email, and a test message
- Click Send
- Check your inbox — the email should arrive within seconds
TIP: If the form hangs, check API Gateway → CORS settings and Lambda → CloudWatch Logs for errors.
Verification Checklist
- SES email address verified — status shows Verified
- IAM role LambdaSESRole created with SESFullAccess and LambdaBasicExecutionRole
- Lambda function ContactFormHandler deployed with correct email addresses
- API Gateway ContactFormAPI created with POST /contact route
- CORS configured with Allow-Origin: *
- contact.html uploaded to S3 with correct API URL
- Form submission sends email to your inbox
What You Learned
- Amazon SES — Simple Email Service, identity verification, and sending transactional email
- AWS Lambda — serverless functions, Python runtime, event handling, and boto3
- Amazon API Gateway — HTTP APIs, routes, Lambda integrations, and CORS
- IAM roles — creating execution roles and attaching managed policies
- Serverless architecture — event-driven, pay-per-use, zero idle cost
Lab Cleanup
IMPORTANT: Delete these resources when finished.
| # | Resource | How to Delete |
|---|---|---|
| 1 | API Gateway | API Gateway → ContactFormAPI → Actions → Delete |
| 2 | Lambda | Lambda → ContactFormHandler → Actions → Delete |
| 3 | IAM Role | IAM → Roles → LambdaSESRole → Delete |
| 4 | S3 contact.html | S3 → your bucket → contact.html → Delete |