circuit

Send Email Attachments with AWS Lambda + AWS Simple Email Service (SES)

How to send email attachments with AWS Lambda and AWS Simple Email Service (SES)




Photo by sue hughes on Unsplash

Progressive web apps, serverless architecture, microservices on cloud… if you have been paying attention to the latest web development trends, you have undoubtedly heard these key phrases. Let us make use of one of them today. Lambda functions are executable functions that are hosted on AWS that only run whenever you invoke or call the Lambda.

But before proceeding further during Corona times —

Yes! you read it right stay home and read my blog coz it is safe :) Now let's move ahead.

One of the major advantages of Lambdas is that you are only charged for the time it takes for the function to run just like Azure function apps that run in consumption plans.

Sending a mail from AWS lambda with an attachment is pretty simple. Just create a *tempfile *module to create a temp dir using mkdtemp(). And then you are ready to dump your JSON data there!

Or you can possibly use ‘tmp’ dir. It is your choice. Here is another way.

tempdir = tempfile.mkdtemp()
path = os.path.join(tempdir)
with open(path + '/temp.json', 'w') as fp:
    json.dump(response_content, fp)

The next step is to write the code for sending emails. But before that register an AWS Simple Simple Email Service. Simply navigate under Email Addresses in the SES console.

I have two code snippets here from the original lambda function. Check them out below:

For a regular email —

And simply call the method using the pattern

send_email('[some_sender@gmail.com](mailto:kuharanbhowmik@gmail.com)', '[some_receiver@gmail.com](mailto:kuharanbhowmik@gmail.com)', 'us-east-1', 'AWS LAMBDA TEST')

Note:

The body can contain either contain html or text not both. The example above has been shown for both options.

  • For emails with attachments, it requires a MIMEMultipart message —
    # Display an error if something goes wrong.
    except ClientError as e:
        return(e.response['Error']['Message'])
    else:
        return("Email sent! Message ID:", response['MessageId'])

JSON to CSV -

And simply call the method using the pattern

json_to_csv(path, '/xxx.json', '/xxx.csv')
send_email('some_sender@gmail.com', 'some_receiver@gmail.com', 'us-east-1', 'AWS LAMBDA TEST', path + '/xxx.json')

In case you want to send it to multiple recipients, you can modify the script like this:

  1. Comment on this line

    msg['To'] = recipient

  2. Modify this part of the code so that ‘Destinations’ accepts a list

    response = client.send_raw_email( Source=msg['From'], Destinations=recipient, RawMessage={ 'Data':msg.as_string(), } )

The call to that would simply have a list in the recipients parameter

send_email('some_sender@gmail.com', ['some_receiver@gmail.com','some_other_receiver@gmail.com'], 'us-east-1', 'AWS LAMBDA TEST', path + '/xxx.json')

IAM Role for the above to work

{
  "Effect":"Allow",
  "Action":[
    "ses:SendEmail",
    "ses:SendRawEmail"
  ],
  "Resource":"*"
}

To further add a trigger to AWS Lambda click on a Cloudwatch Event and add a schedule using the cron pattern. For Cron expression (0 0 1 _ ? _) i.e for 1st day of all months for all years. For more info — https://docs.aws.amazon.com/lambda/latest/dg/tutorial-scheduled-events-schedule-expressions.html

My final design looks like this —

I hope you’d now be able to quickly set up a Cloudwatch + Lambda + SES architecture that needs email attachments.

Thank you for reading!




Continue Learning