Cloud Native Email Automation with AWS SES, Python, Flask, and Jinja2
Email automation is a crucial component of modern enterprise applications, and Amazon Simple Email Service (AWS SES) provides a robust platform for handling scalable email communications. In this comprehensive guide, we'll explore how to create a custom email automation system using AWS SES, Python Flask, and Jinja2 - perfect for businesses seeking secure, cloud-native email solutions.
Overview
We'll build a cloud-native email system that can:
- Generate dynamic email templates
- Create reports using email templates
- Send formatted HTML emails through AWS SES
Setting Up the Email Template System
1. Creating Custom HTML Email Templates
First, let's create a professional HTML email template using Jinja2 for business process automation:
<!DOCTYPE html>
<html>
<head>
<style>
.body {
font-family: Arial, sans-serif;
}
table {
border-collapse: collapse;
width: 100%;
}
th, td {
border: 1px solid black;
padding: 8px;
text-align: left;
}
</style>
</head>
<body>
<div>
<p>Dear {{ full_name }},</p>
<p>Here is your report for {{ today_ordinal_format }}:</p>
<table>
<tr>
<th>Metric</th>
<th>Amount</th>
</tr>
<tr>
<td>Funds In</td>
<td>£{{ fund_in }}</td>
</tr>
<tr>
<td>Funds Out</td>
<td>£{{ fund_out }}</td>
</tr>
</table>
<p>Best regards,<br>
{{ sender_name }}<br>
{{ designation }}<br>
{{ phone_number }}</p>
</div>
</body>
</html>
2. Implementing the Email Microservice API
Let's create a Flask-based microservice API to generate our email templates:
from flask import Flask, Response
from jinja2 import Environment, FileSystemLoader
import boto3
@email_api.route("/template", methods=["GET"])
@user_required()
def get_email_template(access_token):
# Get required parameters
client_id = request.args.get("clientId")
fund_in = request.args.get("fundIn")
fund_out = request.args.get("fundOut")
# Get user details from Cognito
name, designation, phone_number = get_email_signature_details(access_token)
# Generate template
template = email_service.fetch_email_template(
client_id, fund_in, fund_out,
name, designation, phone_number
)
return Response(template, content_type="text/html")
2.1 User Details and Email Signature Management
A key part of our system is retrieving user details from AWS Cognito for email signatures. Here's how we implement this:
def get_email_signature_details(access_token):
"""
Retrieve user details from AWS Cognito for email signature.
Args:
access_token: AWS Cognito access token
Returns:
tuple: (name, designation, phone_number)
"""
client = boto3.client("cognito-idp")
user = client.get_user(AccessToken=access_token)
name = ""
designation = ""
phone_number = ""
for item in user["UserAttributes"]:
if item["Name"] == "name":
name = item["Value"]
elif item["Name"] == "custom:designation":
designation = item["Value"]
elif item["Name"] == "phone_number":
phone_number = item["Value"]
return name, designation, phone_number
2.2 Custom Template Generation
Our scalable template generation process combines authenticated user details with dynamic content:
def fetch_email_template(
self,
client_id,
fund_in,
fund_out,
name,
designation,
phone_number,
):
"""
Generate email template with dynamic content.
Args:
client_id: Client identifier
fund_in: Incoming funds amount
fund_out: Outgoing funds amount
name: Sender's full name
designation: Sender's designation
phone_number: Sender's contact number
Returns:
str: Rendered HTML template
"""
try:
# Initialize Jinja2 environment
env = Environment(loader=FileSystemLoader("templates"))
template = env.get_template("report_email_template.html")
# Get client information
client_basic_info = self._get_client_info(client_id)
full_name = client_basic_info["full_name"]
# Format dates
today = datetime.date.today()
today_ordinal_format = format_ordinal_date(today) # e.g., "1st January 2024"
day_month_year_format_today = today.strftime("%d/%m/%Y")
# Extract first name for personalized signing
sender_first_name = self._extract_first_name(name)
# Render template with all required variables
email_content = template.render(
full_name=full_name,
today_ordinal_format=today_ordinal_format,
day_month_year_format_today=day_month_year_format_today,
fund_in=fund_in,
fund_out=fund_out,
sender_name=name,
designation=designation,
phone_number=phone_number,
sender_first_name=sender_first_name,
)
return email_content
except Exception as e:
return None, str(e)
3. Email: Composition and Sending
The core email sending functionality leverages AWS SES for reliable enterprise communication:
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
def compose_email(client_id, email_content, sender, is_monthly, to_date):
# Create MIME message
msg = MIMEMultipart("mixed")
msg["From"] = sender
msg["To"] = recipients
msg["Subject"] = f"{client_name} - Report {to_date}"
# Attach HTML content
msg_body = MIMEMultipart("alternative")
htmlpart = MIMEText(email_content.encode("utf-8"), "html", "utf-8")
msg_body.attach(htmlpart)
msg.attach(msg_body)
return msg.as_string()
def send_email(email_content):
try:
response = ses_client.send_raw_email(
RawMessage={"Data": email_content}
)
return {"status": "success", "message_id": response["MessageId"]}
except ClientError as e:
raise ServiceException(e.response["Error"]["Message"])
Enterprise-Grade Features and Best Practices
Cloud-Native Template ManagemenT:
- Implement separate template storage using Jinja2's
FileSystemLoader
- Enable DevOps-friendly template versioning
- Support regulatory compliance requireme
Secure Error Handling:
- Implement comprehensive error handling for template generation
- Maintain detailed logging for compliance
- Monitor email delivery status
Enterprise MIME Handling:
- Professional formatting for multipart emails
- Support for rich HTML content
- Maintain consistent branding across templates
Dynamic Content Integration:
- Real-time data injection into templates
- Support for personalized content
- Business process automation integration
Secure Authentication:
- AWS Cognito integration for enterprise security
- Role-based access control
- Audit trail implementation
Security Considerations
- Always validate email recipients
- Use proper authentication for API endpoints
- Sanitize input data before injecting into templates
- Keep AWS credentials secure and use IAM roles
- Implement rate limiting for email sending
Conclusion
AWS SES combined with Flask and Jinja2 provides a powerful foundation for building an email automation system. By following these patterns, you can create a robust, scalable email service that handles both simple and complex use cases.
Remember to:
- Test templates thoroughly before sending
- Monitor AWS SES sending quotas
- Keep templates maintainable and modular
- Handle edge cases and errors gracefully
This system can be extended to handle more complex scenarios like A/B testing, analytics tracking, and dynamic content based on user preferences.