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

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.