Lab Overview
PREREQ: Complete Lab 03 before this lab. You will update the Lambda function and IAM role from Lab 03.
Extend the contact form to also write every submission to an Amazon DynamoDB table. Each entry is emailed via SES AND permanently stored in a NoSQL database you can query, export, and search at any time.
| Service | Purpose | Free Tier |
|---|---|---|
| Amazon DynamoDB | Fully managed NoSQL database — stores every form submission | 25 GB + 25 WCU/RCU free forever |
| AWS Lambda | Updated function writing to DynamoDB AND sending email via SES | 1M requests/mo free |
| Amazon SES | Sends email notification — unchanged from Lab 03 | 62,000 emails/mo free |
| API Gateway | HTTPS endpoint — unchanged from Lab 03 | 1M calls/mo free |
| AWS IAM | Updated role granting Lambda permission to write to DynamoDB | Always free |
Step-by-Step Instructions
1
Amazon DynamoDB
Create the ContactFormSubmissions Table
- Search for
DynamoDBand click it - Left sidebar → Tables → Create table
- Table name:
ContactFormSubmissions - Partition key:
submissionId— Type: String - Table settings: Customize settings
- Capacity mode: On-demand
- Click Create table → wait for status: Active
TIP: On-demand capacity means you pay only per request. At contact form volumes this is effectively free.
2
AWS IAM
Add DynamoDB Permission to LambdaSESRole
- Search for
IAMand click it - Left sidebar → Roles → search for
LambdaSESRole→ click it - Permissions tab → Add permissions → Attach policies
- Search for
AmazonDynamoDBFullAccess→ check it → Add permissions
3
AWS Lambda
Update the Lambda Function Code
Open ContactFormHandler → Code tab. Delete all existing code and paste the following. Replace both email addresses.
import json, boto3, uuid
from datetime import datetime, timezone
ses = boto3.client('ses', region_name='us-east-1')
dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
table = dynamodb.Table('ContactFormSubmissions')
SENDER_EMAIL = 'your-email@example.com' # replace
RECIPIENT_EMAIL = 'your-email@example.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')
sub_id = str(uuid.uuid4())
ts = datetime.now(timezone.utc).isoformat()
# Write to DynamoDB
table.put_item(Item={
'submissionId': sub_id, 'timestamp': ts,
'name': name, 'email': email, 'message': message
})
# Send email via SES
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}\\n'
f'Message: {message}\\n\\nID: {sub_id}\\nTime: {ts}'
}}
}
)
return {'statusCode': 200,
'headers': {'Access-Control-Allow-Origin': '*'},
'body': json.dumps({'message': 'Saved!', 'submissionId': sub_id})}
except Exception as e:
return {'statusCode': 500,
'headers': {'Access-Control-Allow-Origin': '*'},
'body': json.dumps({'error': str(e)})}- Click Deploy → wait for Changes deployed
4
AWS Lambda
Test the Updated Function
Click the Test tab. Create a new test event with this JSON:
{
"body": "{\"name\": \"Test User\", \"email\": \"test@example.com\", \"message\": \"DynamoDB test\"}",
"httpMethod": "POST"
}- Click Test
- Confirm Execution result: succeeded and a
submissionIdin the response - Check your email inbox — the email should arrive with the submission ID
5
Amazon DynamoDB
View Submissions in the Console
- DynamoDB → Tables → ContactFormSubmissions
- Click Explore table items (orange button, top right)
- Click on the item to see all 5 attributes: submissionId, timestamp, name, email, message
- Submit the live form on your website — new items appear instantly
Verification Checklist
- DynamoDB table ContactFormSubmissions created with On-demand capacity — status Active
- LambdaSESRole updated with AmazonDynamoDBFullAccess
- Lambda code updated and deployed — Changes deployed confirmed
- Test event returns succeeded with submissionId in response body
- Email received with submission ID included
- DynamoDB shows the item with all 5 attributes
What You Learned
- Amazon DynamoDB — NoSQL database, On-demand capacity, tables, items, and attributes
- PutItem — writing records to DynamoDB using boto3
- UUID generation — creating unique partition keys for every record
- Multi-service Lambda — one function writing to DynamoDB and calling SES simultaneously
- IAM policy updates — adding permissions to an existing role
Lab Cleanup
IMPORTANT: Delete these resources when finished.
| # | Resource | How to Delete |
|---|---|---|
| 1 | DynamoDB Table | DynamoDB → Tables → ContactFormSubmissions → Delete |
| 2 | IAM Policy | IAM → Roles → LambdaSESRole → detach AmazonDynamoDBFullAccess |