Receiving and Handling Emails with AWS and Amazon SES

Written by emreturgut | Published 2020/06/12
Tech Story Tags: aws | aws-lambda | amazon-web-services | lambda | serverless | email-automation | node.js | nodejs

TLDR Amazon Simple Email Service (SES) and Lambda (Lambda) are required to handle incoming mails. For example; when a user sends an email to [email protected, you will fetch the email data and process it. Lambda is a compute service that lets you run code without provisioning or managing servers. S3 is a storage for the Internet that you can use to store and retrieve any amount of data, at any time, from anywhere on the web. Node.js is a function that will be uploaded as a Lambda function to your AWS account.via the TL;DR App

If you have B2C applications, you have to deal with support tickets and emails. According to user size, it can be difficult to handle emails with a person or manage same email address with multiple people for support mails.
The article’s topic is fetch the incoming mails into your system. For example; when a user sends an email to contact@example.com, you will fetch the email data and process it. For these kinds of processes three Amazon services are required; Simple Email Service (SES), Lambda and S3. And also for Lambda function I will use Node.js so If you are going to use all these processes you are going to need NPM in your environment. Firstly, I want to explain these services for newbies on AWS or these services.
Simple Email Service enables you to send and receive email using a reliable and scalable email platform.
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.
S3 is a storage for the Internet. It is designed to make web-scale computing easier for developers. Amazon S3 has a simple web services interface that you can use to store and retrieve any amount of data, at any time, from anywhere on the web.
Step 1: Initialize your email with AWS SES
In the AWS SES console, click the Email Addresses menu and verify your email.
Note: If you don’t have email client for your domain yet, you can directly set up in AWS Workmail service
Step 2: Set up rule sets with AWS SES
After verify your email address, click Rule Sets in AWS SES menu. In here we create rules, when the email address receive an email.
Add the target address as recipients. After adding it you have to set DNS records for your mail domain.
After that you have to set actions for email.
First of all we have to add S3 action. It means, when someone sends an email to your address. The email data is saved in S3. So create and set S3 bucket as you see below.
After that we need to add one more action for Lambda but we will do it on other steps. After setting of the bucket continue and finish the rule sets.
Now let’s test the process and send an email to address that we set in AWS SES.
As you see in below the receiving mails now are being saved in your S3 bucket.
Step 3: Create Lambda Function
For Lambda function, I added source code in my Github account.
In local machine we will use Serverless Framework for Node.js, so let’s install it.
$ npm install -g serverless
After that we need to configure framework settings with your AWS account. For these process you have to set your AWS IAM credentials.
$ serverless config credentials --provider aws --key PUBLIC_KEY --secret SECRET_KEY
Then let’s create lambda project;
$ mkdir sesReceiver && cd sesRecever
$ serverless create --template sesreceiever --path sesReceiever
Now our Lambda project is created.
handler.js is a function that will be uploaded as a Lambda function to your AWS account. We create a function named postProcess. In the function I receive the email data from our S3 Bucket. Message Id is the name of the mail data file in your S3 bucket.
This step is independent, you can do anything in here. In the function I fetch it directly from S3 then send it my web server with axios. Then process it in my web server.
'use strict';

const AWS = require('aws-sdk');

const s3 = new AWS.S3({
  apiVersion: '2006-03-01',
  region: "eu-west-1",
});

const simpleParser = require('mailparser').simpleParser;
const axios = require('axios')


module.exports.postProcess = async event => {
  const record = event.Records[0];

  const request = {
    Bucket: "contactemails",
    Key: record.ses.mail.messageId,
  };

  try {
    const data = await s3.getObject(request).promise();
    const email = await simpleParser(data.Body);
    const isResult = await axios.post(process.env.targetURL, {
            from: email.from.text,
            subject: email.subject,
            body: email.text,
            attachments: JSON.stringify(email.attachments)
        }).catch( e => console.log(e))
        console.log(isResult)
    return { status: 'success' };
  } catch (Error) {
    console.log(Error, Error.stack);
    return Error;
  }
};
serverless.yml tells Serverless what runtime to use, which account to deploy to, and what to deploy. We should initialize our which IAM profile we are using. Then we need to add which Amazon service we will use. I added S3 and after that we set our S3 bucket, Lambda function.
Finally we need to add S3 bucket permission as Resource.
service: sesreceiver

provider:
  name: aws
  runtime: nodejs12.x
  region: eu-west-1
  profile: # Your aws iam profile
  iamRoleStatements:
    - Effect: Allow
      Action:
        - s3:*
      Resource: "*"

custom:
  bucket: contatctmails

functions:
  postProcess:
    handler: handler.postProcess

resources:
  Resources:
    S3EMailBucketPermissions:
      Type: AWS::S3::BucketPolicy
      Properties:
        Bucket: 
          Ref: # Your bucket ref
        PolicyDocument:
          Statement:
            - Principal: 
                Service: "ses.amazonaws.com"
              Action:
                - s3:PutObject
              Effect: Allow
              Sid: "AllowSESPuts"
              Resource: 
                Fn::Join: ['', ['arn:aws:s3:::', Ref: "contatctmails", '/*'] ]
              Condition:
                StringEquals:
                  "aws:Referer": { Ref: AWS::AccountId }
After the setting up Lambda function, we can deploy it now
$ serverless deploy
Key point in here; our Lambda function and SES service must be set up in same Amazon Region. Personally, I used Ireland.
Now our Lambda function is ready as you see below.
Step 4: Add Lambda function as rule action in SES
Let’s turn back to SES console and rule sets. We should add our function second step of rules.
When an email send to the target address, first email data will be created in our 3 bucket, then our Lambda function will be triggered with message id.
Our Lambda function will get the email data from S3 with message id, in final we will process our email.
In conclusion with using this type of services, you will take advantage from these;
  • You can handle emails with multiple people in your system.
  • You can categorize emails according to content data.
  • You can match email sender with your system directly.
  • You can track your support agents’ action.

Written by emreturgut | Software Engineer
Published by HackerNoon on 2020/06/12