Skip to main content
Edstem Technologies company logo
AWS
AWS SES
Email Automation
Python
Flask
Jinja2

Cloud Native Email Automation with AWS SES, Python, Flask, and Jinja2

by: Sharath Vijayan Nair

January 23, 2025 · 3 min read

Share:
Cloud Native Email Automation with AWS SES, Python, Flask, and Jinja2

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:

html
<!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>

<br>

2. Implementing the Email Microservice API

Let's create a Flask-based microservice API to generate our email templates:

python
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")

<br>

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:

python
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:

python
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:

python
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

<br>

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

<br>

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.

contact us

Get started now

Get a quote for your project.

We use cookies to improve your experience and analyze site traffic. Read our Privacy Policy.