Beginner
Serverless Contact Form
Build a contact form that sends emails using API Gateway, Lambda, and SES
Project Overview
Create a fully serverless contact form that processes submissions and sends email notifications. No servers to manage, and you only pay for what you use.
Prerequisites
- AWS account (Free Tier)
- Basic JavaScript/Python knowledge
- A verified email address for SES
- HTML form on your website
Architecture
Web Form
Frontend
API Gateway
REST API
Lambda
Process Form
SES
Send Email
Optional: Store submissions in DynamoDB for backup
Step-by-Step Instructions
1
Verify Email in SES
- Go to Amazon SES in the AWS Console
- Click "Verified identities" then "Create identity"
- Choose "Email address" and enter your email
- Check your inbox and click the verification link
- Note: In sandbox mode, both sender and recipient must be verified
2
Create the Lambda Function
- Go to Lambda and click "Create function"
- Choose "Author from scratch"
- Name it "ContactFormHandler"
- Select Python 3.12 or Node.js 20.x runtime
- Create a new execution role with basic Lambda permissions
3
Add Lambda Code
- Parse the incoming JSON body (name, email, message)
- Validate required fields
- Use boto3 (Python) or AWS SDK to send email via SES
- Return appropriate response with CORS headers
- Add error handling for failed sends
4
Set Up API Gateway
- Go to API Gateway and create a REST API
- Create a new resource called "/contact"
- Add a POST method
- Connect it to your Lambda function
- Enable Lambda Proxy integration
5
Configure CORS
- Select the /contact resource
- Click "Enable CORS" from the Actions menu
- Set allowed origin to your website domain
- Enable for POST and OPTIONS methods
- Deploy the API to a stage (e.g., "prod")
6
Connect Your Frontend
- Copy the API Gateway invoke URL
- Update your HTML form to submit via fetch/AJAX
- Send POST request with JSON body
- Handle success and error responses
- Test the complete flow
Tips
- Use environment variables for email addresses - Don't hardcode emails in your Lambda code
- Add input validation - Sanitize inputs to prevent injection attacks
- Request SES production access - Submit a request to send to any email address
- Add rate limiting - Use API Gateway throttling to prevent abuse
Code Examples
Lambda Function (Python)
lambda_function.py
PYTHON
import json
import boto3
import os
ses = boto3.client('ses')
def lambda_handler(event, context):
try:
body = json.loads(event['body'])
name = body['name']
email = body['email']
message = body['message']
# Send email via SES
ses.send_email(
Source=os.environ['SENDER_EMAIL'],
Destination={
'ToAddresses': [os.environ['RECIPIENT_EMAIL']]
},
Message={
'Subject': {'Data': f'Contact Form: {name}'},
'Body': {
'Text': {'Data': f'From: {name} ({email})\n\n{message}'}
}
}
)
return {
'statusCode': 200,
'headers': {
'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json'
},
'body': json.dumps({'message': 'Email sent successfully'})
}
except Exception as e:
return {
'statusCode': 500,
'headers': {'Access-Control-Allow-Origin': '*'},
'body': json.dumps({'error': str(e)})
}
Frontend JavaScript
contact-form.js
JAVASCRIPT
const form = document.getElementById('contact-form');
const API_URL = 'https://abc123.execute-api.us-east-1.amazonaws.com/prod/contact';
form.addEventListener('submit', async (e) => {
e.preventDefault();
const data = {
name: document.getElementById('name').value,
email: document.getElementById('email').value,
message: document.getElementById('message').value
};
try {
const response = await fetch(API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (response.ok) {
alert('Message sent successfully!');
form.reset();
} else {
throw new Error('Failed to send message');
}
} catch (error) {
alert('Error: ' + error.message);
}
});
IAM Policy for Lambda
lambda-ses-policy.json
JSON
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ses:SendEmail",
"ses:SendRawEmail"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
}
]
}
What You'll Learn
- API Gateway REST API creation and configuration
- Lambda function development and deployment
- Email sending with Amazon SES
- CORS configuration for cross-origin requests
- IAM roles and permissions for Lambda