Send an email with an attachment in Python via AWS SES
In this tutorial we'll guide you through the process of sending an email with an attachment using AWS SES in Python. You can use this as part of your Python apps to send single or even multiple attachments via AWS SES.
AWS SES Credentials
The first step to sending an email via SES in Python is to configure your AWS credentials. If you haven't already done this, you can set them up by creating a file named ~/.aws/credentials and adding your credentials as follows:
[default]
aws_access_key_id = YOUR_ACCESS_KEY
aws_secret_access_key = YOUR_SECRET_KEY
Make sure of course that you replace YOUR_ACCESS_KEY and YOUR_SECRET_KEY with your actual AWS credentials. You can generate AWS credentials from within your AWS Console.
Now let's get started with writing the Python script to send an email via AWS SES with an attachment. We'll use the "email" library in Python to create the email message and then send it via AWS SES.
First, import the modules we're going to need:
import os
import boto3
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
With the right modules imported we can now work on the Python function that's actually going to send out the email.
Python function for sending SES email
def send_ses_email(subject, body_text, body_html, sender_email, recipient_emails, attachment):
# Create a multipart/mixed parent container
msg = MIMEMultipart('mixed')
msg['Subject'] = subject
msg['From'] = sender_email
msg['To'] = ', '.join(recipient_emails)
# Add body to email
msg_body = MIMEMultipart('alternative')
textpart = MIMEText(body_text.encode('utf-8'), 'plain', 'utf-8')
htmlpart = MIMEText(body_html.encode('utf-8'), 'html', 'utf-8')
msg_body.attach(textpart)
msg_body.attach(htmlpart)
msg.attach(msg_body)
# Attachment
if attachment:
with open(attachment, 'rb') as f:
part = MIMEApplication(f.read())
part.add_header('Content-Disposition', 'attachment', filename=os.path.basename(attachment))
msg.attach(part)
# Connect to AWS SES
client = boto3.client('ses', region_name='us-east-1')
# Try to send the email.
try:
response = client.send_raw_email(
Source=sender_email,
Destinations=recipient_emails,
RawMessage={'Data': msg.as_string()}
)
except Exception as e:
print(e)
return False
return True
As you can see the function above included several paramaters. You'll need to provide each of these with the relevant info when you're using this function in your code.
Sending the email via AWS SES
With the "send_ses_email" function in place we can now trigger it like this.
subject = "Email sent via AWS SES using Python"
body_text = "Content of your email."
body_html = """<html>
<head></head>
<body>
<h1>This email has been sent via AWS SES using Python.</h1>
</body>
</html>"""
sender_email = "hello@example.com"
recipient_emails = ["homer@example.com", "marge@example.com", "lisa@example.com"]
attachment = "path/to/your/attachment.pdf"
# Send the email
send_ses_email(subject, body_text, body_html, sender_email, recipient_emails, attachment)
Notice in the code above that we've defined the recipients to be an array. This makes it easy to send the same email (with the attachment of course) to multiple recipients in one go.
As for the attachment, this just needs to be the full path to the file you want to attach.
It really is as simple as that. With this Python script, you can send emails with attachments using AWS SES. This can be particularly useful for automated email reports, sending documents, or any other case where email attachments are necessary.
Sending multiple email attachments in Python
Whilst this all works great, what if you wanted to be able to send multiple attachments in your email? This is a lot easier to achieve than you may think and can be done with just a few tweaks.
Firstly, lets change our function definition so it accepts an array of attachments instead of just one.
def send_ses_email(subject, body_text, body_html, sender_email, recipient_emails, attachments):
Now let's modify the attachment handling part of the function we made earlier to loop through the list of attachments:
# Attachments
if attachments:
for attachment in attachments:
try:
with open(attachment, 'rb') as f:
part = MIMEApplication(f.read())
part.add_header('Content-Disposition', 'attachment', filename=os.path.basename(attachment))
msg.attach(part)
except IOError:
print(f"Error opening attachment file {attachment}")
continue
This loop will go through each file path in the attachments list, open the file, and attach it to the email. If a file cannot be opened (e.g., it doesn't exist or there are permission issues), the script will print an error message for that specific file and continue with the next one.
Finally, when calling the function, provide a list of attachment file paths:
attachments = ["path/first_attachment.pdf", "path/second_attachment.jpg"]
# Send the email
send_ses_email(subject, body_text, body_html, sender_email, recipient_emails, attachments)
This approach allows you to send multiple attachments in one email. Just list all the attachment file paths in the attachments list when calling the "send_ses_email" function.