DEV Community

loading...

Collect Serverless Email Sign Ups with a Simple AWS Lambda

gjdickens
・3 min read

I run my project Epilocal on Gatsby and AWS. Static sites are great for a lot of reasons, but one of the draw-backs they have is that it's more difficult to handle tasks that would typically be done on the server, like form submissions.

One of the most common situations for this is when you are collecting email sign ups on your site. In a typical set-up with a server, you would be sending your form submission to your server and your server would have a PHP script that would hit the API of your email marketing provider.

But in a serverless set-up, you don't have that option. You might be tempted to just call the email marketing service directly, but you shouldn't be exposing the API key for your email service on the client-side, and many email services prevent you from calling their API from the front-end anyway.

There are some services that have started to pop up and fill this need, but it is pretty easily solved with an AWS Lambda.

Here's the simple Lambda that I use on the Epilocal site:

//index.js
const https = require('https');
const JsonResponse = require('./response');

const defaultOptions = {
    host: 'api.mailerlite.com',
    port: 443,
    headers: {
        'Content-Type': 'application/json',
        'X-MailerLite-ApiKey': 'YOUR_API_KEY',
    }
}

const post = (path, payload) => new Promise((resolve, reject) => {
    const options = { ...defaultOptions, path, method: 'POST' };
    const req = https.request(options, res => {
        let buffer = "";
        res.on('data', chunk => buffer += chunk)
        res.on('end', () => resolve(JSON.parse(buffer)))
    });
    req.on('error', e => reject(e.message));
    req.write(JSON.stringify(payload));
    req.end();
})

exports.handler = async (event) => {
    const { queryStringParameters } = event;
    let postData = { "email": queryStringParameters.email };
    if (queryStringParameters.form_type) {
        postData["fields"] = {"form_type": queryStringParameters.form_type}
    }
    const response = await post("/api/v2/groups/YOUR_GROUP_NUMBER/subscribers", postData);
    let lamdaResponse = new JsonResponse(200, response);
    return lamdaResponse.build();
};
Enter fullscreen mode Exit fullscreen mode
//response.js
class JsonResponse {
  constructor(statusCode, message) {
    this.statusCode = statusCode;
    this.message = message;
  }

  build() {
    return {
      statusCode: this.statusCode,
      headers: {
        "Access-Control-Allow-Origin": "*",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        statusCode: this.statusCode,
        message: this.message,
      }),
    };
  }
}

module.exports = JsonResponse;
Enter fullscreen mode Exit fullscreen mode

You can see the file response.js is just some boilerplate for building a JSON response.

All of the action is happening in index.js. And even here, defaultOptions and the post function are just boilerplate for creating a POST request.

So the only code you really need to pay close attention to is in exports.handler. Here we are parsing the Lambda's queryStringParameters for an "email" parameter and saving that to a new object called postData. Then we are checking if the parameter "form_type" has been provided and if so, we save that to the postData object as well.

Then we are simply passing the postData object into our post function. Note, we are using await here, so exports.handler needs to be an async function.

Finally, we are taking the response that we get from our email marketing service and passing that to our boilerplate JSON response imported from response.js.

I use Mailerlite but you could easily adapt this to whatever email marketing service you use, as long as they have a similar API for adding new subscribers.

Discussion (0)