Simple email forwarding with AWS Lambda and Serverless (and SES)

If forwarding emails (with some calculations in-between) is what you need, then AWS Lambda is the simplest solution for you.

Estimate reading 4 minutes

As the official documentation says:

AWS Lambda is a compute service that lets you run code without provisioning or managing servers. AWS Lambda executes your code only when needed and scales automatically, from a few requests per day to thousands per second.

Lambda

Lambda executes the code (and its dependencies) stored in Functions; We can write a Function directly inside the AWS Lambda or we can use a distinct service to create Lambdas and upload Functions: this service is named Serverless and it does just what we want!

Serverless

Enough talking, let’s dive into some code!

Setup the service

First of all, we want to run npm install serverless -g to install Serverless, and then create our service:

serverless create --template aws-nodejs --path email_sender

Our Serverless project is ready and we just need to setup our AWS IAM credentials that we will store inside ~/.aws/credentials.

Our credentials list looks like this:

[default]
aws_access_key_id=**************
aws_secret_access_key=***************

but if we have more credentials we can use the one we prefer by typing: export AWS_PROFILE="profileName" && export AWS_REGION=eu-west-1 from inside our serverless project.

As soon as we open the project there are two files (and the .gitignore): handler.js and serverless.yml.

serverless.yml determines the structure of our service. We will have something similar to this:

service: email-sender

provider:
  name: aws
  runtime: nodejs4.3

functions:
  send:
    handler: handler.send
    events:
      - http:
          path: submissions
          method: post
          response:
            headers:
              Content-Type: "text/json"
          cors:
            origins:
              - '*'

In this file we can add properties like which packages or plugins we want to upload to Lambda:

package:
  exclude:
    - node_modules/**
  include:
    - node_modules/serverless-offline/**

plugins:
  - serverless-offline

note: serverless-offline is a very useful plugin which allows you to make requests to localhost without having to deploy to Lambda every time you make a change. Run npm install serverless-offline -g to install the offline plugin

The handler.js file is where we will write our methods, the code that we want to execute. From the serverless.yml file we declare which method has to be executed when we call a certain function. So as you might have guessed, in the handler.js file our method will be named ‘send’:

'use strict';
var https = require("https");
var http = require("http");
var AWS = require('aws-sdk');

module.exports.send = (event, context, callback) => {};

We are now ready to do our first deploy.

Deploying to Lambda

serverless deploy will upload the function on a Lambda and gives us back an endpoint to call it, as we can see from the logs:

endpoints:

  POST - https://xxxxxx.execute-api.us-east-1.amazonaws.com/dev/submissions

functions:

  email-sender-dev-send: arn:aws:lambda:us-east-1:32xxxxxx:function:email-sender-dev-send

Adding SES

The last thing we need to look at is the actual email service, which is another Amazon service called SES (Simple Email Service) and it’s very easy to implement:

var ses = new AWS.SES();
ses.sendEmail(params, function(err) {
    callback(null, {
      statusCode: 200,
      headers: {
        "Access-Control-Allow-Origin": "*"
      },
      body: JSON.stringify({ status: "success" })
    });
  })

Sending our first email

By now, `handler.js looks like this:

'use strict';
var https = require("https");
var http = require("http");
var AWS = require('aws-sdk');
var ses = new AWS.SES();

module.exports.send = (event, context, callback) => {
  const data = JSON.parse(event.body);

  const params = {
    Destination: {
      ToAddresses: [ "receiver@example.com" ],
    },
    Message: {
      Subject: {
        Data: data.subject,
        Charset: 'UTF-8'
      },
      Body: {
        Text: {
          Data: data.text,
          Charset: "UTF-8"
        }
      }
    },
    Source: "sender@example.com"
  };

  ses.sendEmail(params, function(err) {
    callback(null, {
      statusCode: 200,
      headers: { "Access-Control-Allow-Origin": "*" },
      body: JSON.stringify({ status: "success" })
    });
  })
};

And we are ready to send! We can try with a simple curl POST request:

curl -H "Content-Type: application/json" -X POST -d '{subject: "test email", text: "this is a test email"}' https://xxxxxx.execute-api.us-east-1.amazonaws.com/dev/submissions

ps: if you are in a SES sandbox you have to verify both sender and receiver emails. As stated in the documentation:

SES

Did you find this interesting?Know us better

Made with Middleman and DatoCMS, our CMS for static websites