Amazon’s Simple Email Service – SES – is a powerful and cost effective to handle any emailing requirements at any scale. This post will cover the basics of setting up a Python Lambda to use the boto3 SDK to send an email via SES. The setup will be defined using Cloudformation – including creating the SES ConfigSet which is definition for SES to handle emails and is required to be able to use SES.
Before we start, please note that in order to use SES we will need either a registered domain or verified email address for SES to use as the from address.
Also, if you are interested in a more complex guide on working with SES with delivery notifications, check out this article. This particular post will cover the basics – just sending the email.
Defining the custom ConfigSet in Cloudformation
Lets start with the yaml definition of the ConfigSet. We will use this ConfigSet to send emails just a little further on in this guide.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: SES Emails with Python and boto3
SESConfigSet:
Type: 'AWS::SES::ConfigurationSet'
Properties:
Name: CustomConfigSet
We are simply going with the defaults. The power of using config sets though comes when you want to get delivery notifications and such which you can do by defining a ConfigSet Destination. This is all covered in the other article linked above but is not going to be covered here.
Defining the Python Lambda and setting IAM permissions to allow it to send email
First lets define the Lambda function yaml. Again, just in case you are not familiar with this setup, take a look at this guide for more details on this section – but basically make sure your lambda file name and location match what you enter in the yaml CodeUri and Handler properties.
EmailLamba:
Type: AWS::Serverless::Function
Properties:
Architectures:
- arm64
Runtime: python3.9
CodeUri: ./email-lambda/
Handler: email-lambda.email_handler
Description: Python Email Lambda
FunctionName: email-lambda
Policies:
- Statement:
- Effect: Allow
Action:
- "ses:SendEmail"
- "ses:SendTemplatedEmail"
- "ses:SendRawEmail"
- "ses:SendBulkTemplatedEmail"
Resource: "*"
Environment:
Variables:
SES_CONFIG_SET_NAME:
Ref: SESConfigSet
The Policies property allows our Lambda to perform the 4 defined Send Email ses operations. This is a necessary part of working with AWS’ fine grained IAM role definitions – and is a very good security and design practice as well – our Lambda will be allowed to do only what it needs to do – which in this case is sending different kinds of emails.
We are also passing the name of the ConfigSet, “CustomConfigSet”, which we defined in the previous section to the Lambda as an environmental variable.
Coding the Python Lambda to send emails
As mentioned, we are going to use the boto3 SDK to send an email using the ConfigSet we created above.
First let the code below sink in…
import os
import boto3
import json
from datetime import datetime
from_email = "email@my_verified_domain.com"
config_set_name = os.environ["SES_CONFIG_SET_NAME"]
client = boto3.client('ses')
def email_handler(event, context):
body_html = f"""<html>
<head></head>
<body>
<h2>Email from AWS SES!</h2>
<br/>
<p>This was sent from a Python Lambda using boto3</p>
</body>
</html>
"""
email_message = {
'Body': {
'Html': {
'Charset': 'utf-8',
'Data': body_html,
},
},
'Subject': {
'Charset': 'utf-8',
'Data': "Hello from AWS SES",
},
}
ses_response = client.send_email(
Destination={
'ToAddresses': ['to@some_email.com'],
},
Message=email_message,
Source=from_email,
ConfigurationSetName=config_set_name,
)
print(f"ses response id received: {response['MessageId']}.")
You probably got the idea, but to break it down, we defined the html section of the email – this can get as complex as you need it to be with styling and and email html template libraries – ours is pretty bare bones for a demonstrative purpose. We have our email message object for the boto3 library – which has the body we defined and the subject. And finally we send the email out providing the to, from addresses and the ConfigSet to use.
Concluding
This covers the basics to get started and going. The next steps would be to integrate the Lambda with the inputs such as dynamic to addresses and also using other types of email and handling text based emails where clients don’t have html support – all of which is well supported in SES.