Handle Incoming Emails Using AWS SES and SNS
Handle Incoming Emails Using AWS SES and SNS

Handle Incoming Emails Using AWS SES and SNS

Spread the love
Handle Incoming Emails Using AWS SES and SNS | Flow Diagram of incoming Email handler
Flow Diagram of incoming Email handler

Amazon SES is a simple email service used to send and receive emails from your verified domain using any application. AWS SNS is a Simple Notification Service used to notify/publish messages from an application to the subscribed endpoint user/server & customers. In my previous article(read here), I had discussed how to send email using AWS SES, in this article we are going to learn how to receive email using AWS SES & AWS SNS.


Step 1. AWS Setup

  1. Create an AWS account here https://portal.aws.amazon.com/billing/signup#/start
  2. Now go to IAM(Identity and Access Management — IAM user creation is required for giving access to your application to perform the action.)
    a. Add new User
    b. Select AWS access type as“Programmatic access”
    c. Set permissions -> Attach existing policy -> i. AmazonSESFullAccess ii. AmazonSNSFullAccess
    d. select the permission Boundry
    e. give the tag
    f. Review & create a user.
    g. download the access key & Id for future use.
  3. Go to SES ->Domains -> Verify New domain. This step is necessary to allow SES to process the incoming email.

Step 2. Node.js Setup

1. Install AWS-SDK & mail parser using npm or bower:

npm i aws-sdk
bower install aws-sdk-js
npm i mailparser

2. Store AWS access key & secret access to config.js file:

{
 "accessKeyId":"AWS_ACCESS_KEY_ID",
 "secretAccessKey":"AWS_SECRET_ACCESS_KEY",
 "region":"AWS_DEFAULT_REGION"
}

3. Let’s create an SNS-helper.js to notify about incoming email

a. Import AWS module:
const AWS = require('aws-sdk')
const config = require('../config.json')
b. Initialize SNS instance with access info:
const snsConfig = {
 apiVersion: '2010-03-31',
 accessKeyId: config.accessKeyId,
 secretAccessKey: config.secretAccessKey,
 region: config.region,
}
const SMS = new AWS.SNS(snsConfig)
c. create a topic & subscription endpoint to notify about incoming email
module.exports.createTopic = async() => {
 const topic = await sns.createTopic({
   Name: 'receive-email-poc',
   Attributes: {
    FifoTopic: true,
    DisplayName: 'Receive-email'
   }
  }).promise()
const params = {
   Protocol: 'HTTPS',
   TopicArn: topic.TopicArn,
   Attributes: {
    RawMessageDelivery: false,
   },
   Endpoint: 'https://app.example.com/emails/receive-email',
  };
 const subscription = await sns.subscribe(params).promise();
}

Creation of topic is required to notify our server/your email about incoming emails.

  1. Create the topic with a name & attribute. Topics in AWS are communication channel which allows us to group multiple endpoints where SNS will notify the specific event action.
  2. Create a subscription to register the server endpoint where we want notification. Topic ARN is a unique id of the topic.
  3. Confirm the subscription & AWS will send a notification to the endpoint.

4. Let’s create a ses-helper.js to set up rules of incoming email

a. Import AWS module:
const AWS = require('aws-sdk')
const config = require('../config.json')
b. Initialize SES instance with access info:
const sesConfig = {
 apiVersion: '2010-12-01',
 accessKeyId: config.accessKeyId,
 secretAccessKey: config.secretAccessKey,
 region: config.region,
}
const ses = new AWS.SES(sesConfig)
c. Create Rule Set & rules to setup incoming emails
module.exports.createRules = async () => {
  const ruleSet = await ses.createReceiptRuleSet({
    RuleSetName: 'ReceiveEmails-POC'
  }).promise()
  const params = {
    After: "",
    Rule: {
     Name: "S3Rule",
     Enabled: true,
     TlsPolicy: "Optional",
     Actions: [{
      S3Action: {
       BucketName: "EmailBucket",
       ObjectKeyPrefix: "email",
       KmsKeyArn: "arn:aws:kms:.....",
       TopicArn: "arn:aws:sns:......"
      }
     }],
    Recipients: [
     "@example.com",
     "@email.example.com",
    ],
    ScanEnabled: true,
   },
   RuleSetName: "ReceiveEmails-POC"
  };
 const rules = await ses.createReceiptRule(params).promise()
}

You need to set certain rules to accept the incoming emails like first create ruleset which is a group of rules to be applied when SES receives an email. Then create individual rules to the set like

i. Rule object contains:
  • a. Name specifies the name of the rule.
  • b.Enabled specifies whether this rule is activated or not.
  • c.TlsPolicy specifies whether SES should require that incoming email is delivered over a connection encrypted with Transport Layer Security (TLS). If this parameter is set to “Require”, Amazon SES will bounce emails that are not received over TLS. The default is “Optional”.
  • d. Recipients specifies an array of domains or email address that the receipt rule applies to. If this field is not specified, this rule will match all recipients under all verified domains.
  • e. ScanEnabled specifies boolean value, if set to true it will scan the email for spam and virus.
  • f. Actions contain an array of actions to be applied when this rule is activated like perform s3action which means storing the incoming email into the S3 bucket. If the topic ARN is specified it will notify the subscriber of the SNS topic. KmsKeyArn specifies the customer master key that Amazon SES should use to encrypt incoming emails before saving them to the S3 bucket. There are other actions available to be performed for setting rules like directly send the mails to SNS subscribers using SNSAction. You can read more action here.

ii. RuleSetName specifies this rule belongs to which Rule Set.
iii. After specifies the name of an existing rule after which the new rule will be placed. If this parameter is not specified, the new rule will be inserted at the beginning of the rule list.

You need to create these rules for the first time. After this rule is processed you can reply to a specified domain and you will receive it in your S3 bucket.

5. create an email-receiver.js file in your node project to process incoming emails.

const { simpleParser } = require('mailparser')
const AWS = require('aws-sdk')
const S3 = new AWS.S3({
 apiVersion: '2006-03-01',
 accessKeyId: config.accessKeyId,
 secretAccessKey: config.secretAccessKey,
 region: config.region
})
router.post('/emails/receive-email', async(req, res) => {
 try {
  const message = JSON.parse(req.rawBody)
  const s3Data = await S3.getObject({ 
    Bucket: 'EmailBucket',  
    Key: message.mail.messageId 
   }).promise()
  const parsed = await simpleParser(s3Data.Body)
  let emailResponse = parsed.text
  console.log(emailResponse)
  res.status(200)
 }
 catch (err) {
  console.log(err)
  res.status(501)
 }
})

Once you receive the incoming email you need to parse it to read. We are using a mail parser to read the incoming email. Each incoming email contains a messageId that is unique to store the message. We can access the email from the S3 bucket using messageId. Once you parse the email, it will give you data like HTML format of the message, text format of the message, CC, BCC, subject, reply to, and much more.

That’s it. You can set up incoming emails to reroute to your specified email address.

Thank you for reading.

27 Comments

  1. Cool. I spent a long time looking for relevant content and found that your article gave me new ideas, which is very helpful for my research. I think my thesis can be completed more smoothly. Thank you.

  2. g

    Hi, і think tһat i saw you visited my web site so
    i came to “return the favor”.I am tryіng to find things to enhance my website!I suppose
    its ok tߋ use а few of your ideas!!

  3. Pingback: AWS SES, SNS, CloudWatch Integration with Node.js | Noob2Geek

Leave a Reply

Your email address will not be published. Required fields are marked *