Adding a Contact Form to Your Static Site
Want to add a contact form to your simple static site? Here’s how to do it with near-zero costs, easy setup, and easy teardown if you want to replace the backend with your own server-based application.
Architecture
In short, we want:
- A simple form a user can enter their email, phone, name, and a short message
- Notifications when that form is submitted
To keep this simple and cheap, we will use the Serverless framework to build out the infrastructure on Amazon’s Web Services.
Creating the Serverless Infrastructure
Serverless can create a project skeleton for us with:
serverless create --template aws-nodejs --path contact-lambda
Update your generated serverless.yml
with the minimal AWS configuration we
need for SNS notifications.
# serverless.yml
service: contact-lambda
provider:
name: aws
runtime: nodejs6.10
region: us-east-1
iamRoleStatements:
- Effect: Allow
Action:
- 'sns:Publish'
Resource:
Ref: ContactTopic
functions:
Notify:
handler: handler.notify
memorySize: 128 # Reduce costs by minimizing resources allocated to lambda
events:
- http:
path: notify
method: post
cors: true
environment:
TOPIC_ARN:
Ref: ContactTopic
resources:
Resources:
ContactTopic:
Type: AWS::SNS::Topic
Properties:
DisplayName: 'Contact Topic'
TopicName: 'contact-topic'
Subscription:
# Add any emails or SMS numbers you would like notified
- Endpoint: '[email protected]'
Protocol: 'email'
- Endpoint: '5555555555'
Protocol: 'sms'
Run serverless deploy
to create your infrastructure. Make note of the POST
endpoint created:
$ sls deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service .zip file to S3 (58.06 KB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
..........
Serverless: Stack update finished...
Service Information
service: contact-lambda
stage: dev
region: us-west-2
stack: contact-lambda-dev
api keys:
None
endpoints:
POST - https://abcdefghi1.execute-api.us-east-1.amazonaws.com/dev/notify
functions:
Notify: contact-lambda-dev-Notify
Serverless: Removing old service versions...
Now that we have the infrastructure in place, let’s modify the Lambda handler to send notifications when forms are submitted.
Form handling
We want our handler to handle form submissions like
<!-- test.html -->
<form
action='https://abcdefghi1.execute-api.us-east-1.amazonaws.com/dev/notify'
method='post'
>
<label>
Email
<input type='text' name='email'>
</label>
<label>
Name
<input type='text' name='name'>
</label>
<label>
Message
<input type='text' name='message'>
</label>
<label>
Phone
<input type='text' name='phone'>
</label>
<input type='submit'>
</form>
We’ll use a couple Node packages to simplify form parsing.
yarn add html-entities qs
Our handler is then responsible for sending a SNS message to our notification topic.
// handler.js
'use strict'
const AWS = require('aws-sdk')
const sns = new AWS.SNS()
const qs = require('qs')
const Entities = require('html-entities').XmlEntities
const entities = new Entities()
const formKeys = ['email', 'message', 'phone', 'name']
module.exports.notify = (event, context, callback) => {
const body = qs.parse(event.body)
const message = formKeys
.map(key => `${key}:${entities.decode(body[key])}`)
.join('\n')
sns.publish(
{
Message: message,
Subject: 'New contact form submitted',
TopicArn: process.env.TOPIC_ARN
},
(err, result) =>
callback(null, {
statusCode: err ? '500' : '201',
body: err ? err.message : JSON.stringify(result),
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}
})
)
}
And that’s it! Redeploy with serverless deploy
, and you can start sending
notifications when forms are submitted.
The result
When your topic and subscriptions are created, you will receive an email or SMS message from AWS asking you to confirm your subscription to the notification topic.
Confirm your subscription, and any form submissions will send you a notification with the form contents.
Not pretty, but perfect for internal notifications, especially since subscriptions are automatically managed for you! You form handler can also be extended with Slack or other application integrations.