Receive and process emails with AWS SES [Simple Email Service]
Simple Email Service (SES) is an email service by AWS suited for various use cases that allows sending and receiving emails.
We can also intercept and process incoming emails, extract attachments, forward the email to another mailbox or just save it in s3 just in 2 simple steps.
In my use case, I wanted to extract the attachments and save them in an s3 bucket. The flow diagram looks something like this.
Step 1: Verify Your Domain
- Go to Verified Identities in SES Dashboard on AWS Console and create an identity.
- Select “Domain” as the identity type and enter the domain through which you would like to receive the emails and click on “Create Identity” at the bottom of the screen.
- Once the identity is created, add the DNS records (3 CNAME records) to your DNS Manager (If your domain is present in Route 53, they are automatically added)
Once the Identity is verified using the DNS records, We should be able to send emails from the identity. However, to receive the emails, we need to add another DNS record to the DNS Manager.
NAME: example.com (your domain name in verified identity)
TYPE: MX
VALUE: inbound-smtp.<aws-region>.amazonaws.com (ex: <aws-region> could be us-east-1)
PRIORITY: 10
Now we should be able to receive all the emails that are sent to the email addresses belonging to the verified identity. However, since we do not have a mailbox, we will not be able to read these emails.
Step 2: Define RuleSets
- Navigate to “Email receiving” under “Configuration” in the SES Dashboard.
- In the “Receipt Rule Sets” tab, create a rule set.
- Open the newly created Rule set and create a rule.
- step1: Provide the name of your rule and click next.
- step2: Add recipient conditions. You can add multiple conditions. In my case, I would like to receive all the emails in my domain.
- step3: Add Actions. You can add multiple actions depending on what you want to do with your emails. In my case, I save the incoming emails to an S3 bucket and invoke a lambda function in the 2nd action to process the email and extract the attachments and save them in a different S3 bucket.
You can now review and save the rule. - My lambda Function looks something like this.
import email
import boto3
import json
import requests
read_bucket = 'incoming-email'. # name of the bucket where the emails are saved
s3 = boto3.resource('s3')
write_bucket = 'attachment buckets' # name of the bucket where the attachments are to be saved
def lambda_handler(event, context):
messageID = event['Records'][0]['ses']['mail']['messageId']
# get the email from s3
key = f'incoming/{messageID}'
read_obj = s3.Object(read_bucket, key)
body = read_obj.get()['Body'].read().decode('utf8')
# get attachments from email body
msg = email.message_from_string(body)
payloads = msg.get_payload()
# convert the attachments into files and upload to s3
for attachment in payloads[1:]:
name = attachment.get_filename()
data = attachment.get_payload(decode=True)
key = f'{name}'
s3.Bucket(write_bucket).put_object(Key=key, Body=data)
# delete the email from s3 (optional)
read_obj.delete()
return {
'statusCode': 200,
'body': json.dumps('Email Processed Successfully')
}
- Finally, make sure you set the rule set as active before you test your setup.
Now you should be able to send emails to the domain and the emails will be saved to s3 and then the lambda is invoked and the email is processed.
Further Work:
- Emails can be encrypted using KMS Keys in order to not keep these emails as plain text. Find more
- Make sure the S3 and the SES are encrypted using the same KMS keys.