How to build a serverless contact form on AWS
Jun 08, 2023 • 11 Minute Read
The contact form is critical to all websites, small and large. There are many services available to embed contact forms into your own website, but this tutorial is not about leveraging those services. Instead, it is about learning a handful of Amazon Web Services by focusing on the problem of creating our own contact form architecture. By the end of this guide, we will have created a serverless contact form and learned more about the following services:
Keep up with other projects Kyle is working on by following him on Twitter, LinkedIn, and Medium.
- API Gateway
- Lambda
- Simple Email Service
{“email”: <contact-email>,“subject”: <contact-subject>,“message”: <contact-message>}
This endpoint will have a Lambda function behind it that will turn the request body into an email. That email request will sent to Simple Email Service (SES) for delivery. With those pieces in place, we can then create a contact form that sends the message.
Configuring Simple Email Service to send us email
Before diving into any code, we need to configure Simple Email Service (SES). Our Lambda function is going to process the message from our website and send the email via SES.SES is a slick offering for both delivering and receiving email. It offers high deliverability, cost effectiveness, and very reliable email processing.In this post, we are going to leverage it to take a message and send it to our own whitelisted email address. For the purposes of the project we’re creating, we can do everything within the SES sandbox environment. The sandbox environment has the following limitations:- Can only send email to the SES mail box simulator or to email addresses or domains that you have verified.
- Limited to sending 200 emails per day.
- Navigate to Simple Email Service in the AWS Console.
- Click Email Addresses
- Click Verify a New Email Address
- Enter the email address you would like to use for contact requests.
- Click Verify This Email Address
- Check your email for a verification email with subject “Amazon Web Services – Email Address Verification Request”
- Click the link in the email to confirm your email address.
Setting up your initial Lambda function to respond to API Gateway triggers
You got your SES setup squared away? Your email address is a verified email address that SES can send email to? Then you're making excellent progress already.Since the debut of Lambda functions in November 2014, Amazon Web Services has streamlined their creation. It used to be the case that configuring a Lambda for different AWS events was tedious and error prone. Today, the initial setup is more streamlined and user friendly. This is great for us, but do know that we will have to do some further tweaking later on.But first, let’s get our initial Lambda set up and triggered from an API Gateway endpoint.The backbone of the serverless stack is an event. An event kicks off the allocation of compute resources to complete some action. A trigger in AWS is the event that will allocate a container to execute the code in your Lambda function. Within AWS there are currently 17 different events that Lambda can respond to.Today, we are leveraging the API Gateway event via an HTTP endpoint. Think of the HTTP endpoint as triggering an event for our Lambda function. The request starts the container and includes the input event to our Lambda function. Using this input, we can process the message in our code.How about we jump in and configure the initial endpoint and Lambda function:- Navigate to Lambda from the AWS Console.
- Click Create function
- In the Blueprints input, enter “api”
- Click the blueprint “microservice-http-endpoint” in NodeJs 6.10.
- For “API name”, click Enter value and enter “contact”
- For “Deployment stage”, leave the default “prod” selected.
- For “Security”, select “Open”
- Click Next
- Enter “ContactFormLambda” for your function Name.
- Enter a meaningful description like “Process APIGW POST to /contact”
- Select “Node.js 6.10” for the Runtime.
- For now, we are going to enter this boilerplate code in the inline-code section:
- In the “Lambda function handler and role”, leave Handler at “index.handler”. Role should be “Create new role from template(s)”. For role name, enter “ses-contact-form-lambda”. For policy templates, select “Simple Microservice permissions”Note: We will do more configuration around these areas later on.
- Click Next
- Click Create function
- An API Gateway endpoint that will proxy HTTP(S) requests.
- A Lambda function that your API Gateway endpoint triggers.
- An IAM role “ses-contact-form-lambda” that has the basic execution policy for Lambda.
Configure your IAM Role to send email via SES
Before we start writing our Lambda function, we need to take a pause and configure the ses-contact-form-lambda IAM role. Currently, the role is not allowed to use the sendEmail API in SES.To make this very lightweight, we’ll create a new IAM policy that has only the API on SES that we need to grant access too.- Navigate to IAM from the AWS Console.
- Click Policies
- Click Create Policy
- Select “Create Your Own Policy”
- Enter “contact-form-send-email-policy” for the Name.
- Configure the Policy Document as follows:
- Click Create Policy
- Navigate to IAM from the AWS Console.
- Click Roles
- In search enter “ses-contact-form-lambda”
- Click “ses-contact-form-lambda” role.
- Click Attach Policy
- Select “contact-form-send-email-policy”
- Click Attach Policy
Sending email via SES from your Lambda function
We now have all the finalized infrastructure pieces for your serverless contact flow. That only took a few button clicks and, voila--we have the API Gateway, Lambda function, and IAM role. Pretty slick, right?The infrastructure, at this point, is not yet ready for primetime. We will make it so in a bit, but first let’s add the code for sending email via SES from your Lambda function. There are no external dependencies in our function. Because of this, we can edit the code inline. If we were creating Lambda functions that require other NPM modules we would need to develop outside of the AWS Console. The reason is because when zip files get uploaded to Lambda, NPM packages must be included.But that is not the focus of this project. We are going to edit the code inline because we have no external dependencies.- Navigate to Lambda from the AWS Console.
- Click the “ContactFormLambda” function.
- Enter the following code into the inline editor:
Showtime - time to test your endpoint
You updated your Lambda function code to the above. You have sesConfirmedAddress set to the verified SES email. The IAM role for the Lambda has access to the sendEmail API of Simple Email Service. All we have left is to test and see if it works.As the old adage goes, if you haven’t tested it, then it doesn’t work. For the purposes of this project I am talking about verifying that it works by using it and observing the results. There are other levels of testing that we should do here if we were building a full production app. Unit tests and integration tests would be great things to add. But for this simple contact flow, let’s just make sure it works from our API Gateway.- Navigate to API Gateway from the AWS Console.
- Click the “contact” API.
- Click ANY under the “/ContactFormLambda” resource.
- Click TEST
- Select “POST” for Method.
- In the Request Body enter the following:
- Click Test
- Method completed with status: 200 -- Awesome it worked! Check your email.
- Method completed with status: 500 -- Darn it broke. Time to check the logs.
- Method completed with status: 502 -- Configuration error. Time to check the logs.
- Navigate to CloudWatch from the AWS Console.
- Click Logs
- In the “Log Group Name Prefix” enter “/aws/lambda/ContactFormLambda”
- Click “/aws/lambda/ContactFormLambda”
- Typos in things you weren’t expecting
- Not assigning the right IAM policy to the right IAM role
- Misconfigured Lambda function--incorrect memory allocation or time allocation
Enable CORS and publish your API
Before your functioning API is ready for the wild wild west, you have a few final knobs to turn.The first thing we need to do is enable Cross Origin Resource Sharing (CORS) on our API endpoint. This grants endpoint access to domains we specify. The last thing will be to publish our API to a public stage.First, let’s go ahead and turn CORS on for this endpoint:- Navigate to API Gateway from the AWS Console.
- Click the “contact” API.
- Click “ContactFormLambda” resource.
- Click Actions
- Select “Enable CORS”
- In “Access-Control-Allow-Origin” enter the URL of the website you are going to call this endpoint from. If you are unsure, leave it as ‘*’ which will allow any domain.
- Click Enable CORS...
- Click Yes, replace existing values
- Navigate to API Gateway from the AWS Console.
- Click the “contact” API.
- Click “ContactFormLambda” resource.
- Click Actions
- Click Deploy API
- Select “prod” from Deployment stage.
- Click Deploy
Integration
At this point, we have a functional serverless contact flow. API Gateway calls a Lambda function. That function takes the request body and sends it via Simple Email Service.The next step is to integrate this new API of yours into something of your choosing. You can start with your own website or portfolio page. To integrate it, create a form with the same fields as the request body requires--the user’s email address for replies, the subject, and the body. On form submission, add a quick AJAX request in JavaScript with the request body and you should be off to the races.Update: We've created a follow-up guide that continues from where we left off here, and integrates the service into a web page. You can check it out here.Conclusion
There is a vast sea of information out there around AWS. So much so that it can be easy to get lost in trying to learn it. The best way to learn anything is to start using it. By following along, you've learned the concepts of API Gateway, Lambda, and SES by using them in a practical problem.This is the way I first learned AWS. It is what I still do today as a Certified Professional Solutions Architect. If you have any questions please feel free to reach out to me. If you want to learn about AWS by creating more projects like this one, check out my upcoming book, How To Host, Deliver, and Secure Static Websites on Amazon Web Services.Keep up with other projects Kyle is working on by following him on Twitter, LinkedIn, and Medium.