AWS Contact Center

Automating Pinpoint email template migration to Amazon SES v2

If you manage email templates in Amazon Pinpoint and need to migrate them to Amazon Simple Email Service (Amazon SES) v2 before the October 30, 2026 end of support deadline, you know the challenge: renaming fields, converting placeholder syntax, handling click-tracking attributes, and deploying at scale, all tedious and error-prone when done manually across dozens or hundreds of templates.

In this post, you learn how to use migrate_pinpoint_to_sesv2.py, an open-source Python script (available on GitHub), to automate the end-to-end conversion. The script converts Pinpoint templates to Amazon SES v2 format, validates them against service limits, and deploys them directly. In our testing, the script migrated 100 sample templates in under 5 minutes, with no manual field renaming required for standard templates.

Whether you have one template or hundreds, the script provides a repeatable, auditable migration path with dry-run previews and JSON reporting.

Background knowledge

You should be familiar with the following:

  • Managing an AWS account
  • Amazon Simple Email Service (Amazon SES)
  • Amazon Pinpoint email templates
  • AWS CLI v2
  • Basic Python usage (running scripts from the command line)

Download the script before starting the walkthroughs:

git clone https://github.com/arabam-git/amazon-pinpoint-to-ses-email-template-migrator.git
cd amazon-pinpoint-to-ses-email-template-migrator

What changes between Pinpoint and Amazon SES templates

Amazon Pinpoint and Amazon SES v2 both use HTML email templates with placeholder variables, but there are differences in structure and syntax that you must address during migration, as shown in the following table.

Aspect Amazon Pinpoint Amazon SES v2
Template fields HtmlPart, TextPart Html, Text
Placeholder syntax {{User.UserAttributes.FirstName}} {{firstName}} (simple Handlebars)
Simple placeholders {{FirstName}} {{FirstName}} (no change needed)
Link click tracking ses:tags attributes may appear on <a> tags (passed through to SES) Click tracking enabled per configuration set; ses:tags add custom tags to click events
Template size limit N/A 500 KB per template
Template storage Pinpoint project Amazon SES account (up to 20,000 per Region)

Solution overview

The migration script automates the following workflow:

  1. Load templates from local JSON files, local HTML files, or directly from the Pinpoint API.
  2. Convert to Amazon SES v2 format: rename HtmlPart to Html, TextPart to Text, and convert nested placeholders to simple Handlebars syntax.
  3. Validate: check the 500 KB size limit and flag issues.
  4. Output: save converted JSON to disk, generate a dry-run report, optionally strip ses:tags attributes, and optionally inject an unsubscribe link.
  5. Deploy to Amazon SES v2: create or update templates through the API.
  6. Generate a JSON audit report with per-template details for review.

The script supports three input sources:

  • Local JSON files: Pinpoint template exports containing TemplateName and TemplateContent.
  • Local HTML files: raw .html/.htm files; the script extracts the <title> tag as the Subject and generates a plain text version from the HTML.
  • Pinpoint API: fetches templates directly from the Pinpoint service using --from-pinpoint.

Prerequisites

Before you begin, complete the following prerequisites:

  • Python 3.8–3.12 (tested on 3.9, 3.11, and 3.12; standard library only for dry-run and local conversion)
  • boto3 (latest version recommended; required only for --deploy and --from-pinpoint): pip3 install boto3
  • AWS CLI v2 installed and configured with credentials
  • A verified sending domain or email address in Amazon SES
  • The migration script (see Download the script under Background knowledge)
  • AWS Identity and Access Management (IAM) permissions:
    • For deployment: sesv2:CreateEmailTemplate, sesv2:UpdateEmailTemplate
    • For Pinpoint API fetch: pinpoint:ListTemplates, pinpoint:GetEmailTemplate
    • For sending test emails: sesv2:SendEmail

Walkthrough: Convert and deploy a single template

This section uses a single HTML email template to demonstrate the end-to-end migration process.

Step 1: Prepare your template directory

Create a working directory and place your Pinpoint template in it:

mkdir ses-migration
cp WelcomeEmailTemplate.html ses-migration/

Step 2: Preview the conversion with dry-run

Run the script in dry-run mode to see what changes without making any modifications:

python3 migrate_pinpoint_to_sesv2.py --local-dir ses-migration --dry-run

The dry-run report shows the following:

  • Placeholder mappings (Pinpoint syntax to Amazon SES Handlebars)
  • ses:tags attributes found and whether they will be stripped or kept
  • Template size relative to the 500 KB Amazon SES limit
  • Structure changes (HtmlPart to Html, TextPart to Text)
  • An HTML preview of the converted template

Review the report to confirm the conversion is correct before deploying.

Step 3: Deploy to Amazon SES v2

python3 migrate_pinpoint_to_sesv2.py --local-dir ses-migration --region us-east-1 --deploy

The script creates the template in Amazon SES. If a template with the same name already exists, it updates the template automatically. The deployment summary shows how many templates were created, updated, skipped, or failed.

Step 4: Verify the template

aws sesv2 get-email-template --template-name WelcomeEmailTemplate --region us-east-1

Step 5: Send a test email

aws sesv2 send-email \
  --from-email-address sender@yourdomain.com \
  --destination '{"ToAddresses":["test@yourdomain.com"]}' \
  --content '{"Template":{"TemplateName":"WelcomeEmailTemplate","TemplateData":"{\"FirstName\":\"Jane\"}"}}' \
  --region us-east-1

Every placeholder in the template must have a matching key in TemplateData. If the template contains {{FirstName}} and you do not pass FirstName, Amazon SES returns a Rendering Failure.

Monitoring template rendering failures with a configuration set

After you migrate templates, the most common issue is a Rendering Failure: Amazon SES cannot render the template because a placeholder is missing from TemplateData. Amazon SES does not send the email, and the SendEmail API does not return an error. The only way to catch these failures is by setting up event notifications on a configuration set.

This is especially important after migration because the script converts placeholder names (for example, User.UserAttributes.FirstName becomes firstName). If your sending code still passes the old key names, Amazon SES fails to render the template and does not deliver the email.

Step 1: Create a configuration set

aws sesv2 create-configuration-set --configuration-set-name MigrationMonitoring --region us-east-1

Step 2: Create an Amazon Simple Notification Service (Amazon SNS) topic for notifications

aws sns create-topic --name ses-rendering-failures --region us-east-1

Subscribe your email to the topic so you receive alerts:

aws sns subscribe \
  --topic-arn arn:aws:sns:us-east-1:YOUR_ACCOUNT_ID:ses-rendering-failures \
  --protocol email \
  --notification-endpoint your-email@yourdomain.com \
  --region us-east-1

Step 3: Add a Rendering Failure event destination

aws sesv2 create-configuration-set-event-destination \
  --configuration-set-name MigrationMonitoring \
  --event-destination-name RenderingFailures \
  --event-destination '{
    "Enabled": true,
    "MatchingEventTypes": ["RENDERING_FAILURE"],
    "SnsDestination": {"TopicArn": "arn:aws:sns:us-east-1:YOUR_ACCOUNT_ID:ses-rendering-failures"}
  }' \
  --region us-east-1

Step 4: Send emails using the configuration set

Add --configuration-set-name to your send calls:

aws sesv2 send-email \
  --from-email-address sender@yourdomain.com \
  --destination '{"ToAddresses":["test@yourdomain.com"]}' \
  --content '{"Template":{"TemplateName":"WelcomeEmailTemplate","TemplateData":"{\"FirstName\":\"Jane\"}"}}' \
  --configuration-set-name MigrationMonitoring \
  --region us-east-1

If a placeholder is missing from TemplateData, Amazon SES publishes a RENDERING_FAILURE event to your Amazon SNS topic. The event payload includes the template name and the specific error, letting you catch mismatches between your migrated templates and your sending code before they affect production email delivery.

Walkthrough: Migrate multiple templates

When migrating more than one template, use the --report flag to generate a JSON audit file for review before deploying.

Step 1: Dry-run with a JSON report

python3 migrate_pinpoint_to_sesv2.py --local-dir all-templates/ --dry-run --report migration-report.json

The JSON report includes per-template details: placeholder mappings, ses:tags removed, template size, and whether the unsubscribe link was injected. Review this report to catch any issues before deploying.

Step 2: Deploy all templates

python3 migrate_pinpoint_to_sesv2.py --local-dir all-templates/ --region us-east-1 --deploy

The deployment summary shows counts for created, updated, skipped, and failed templates. If any templates fail, the script exits with code 1 and lists the failures.

Walkthrough: Fetch templates directly from Pinpoint API

If your templates have not been exported to local files, the --from-pinpoint flag tells the script to pull them directly from the Pinpoint API. The script calls pinpoint:ListTemplates to discover all email templates in the account. It then calls pinpoint:GetEmailTemplate for each one to retrieve the full content (Subject, HtmlPart, TextPart). No manual export step is needed.

Preview the templates:

python3 migrate_pinpoint_to_sesv2.py --from-pinpoint --region us-east-1 --dry-run

Deploy the templates:

python3 migrate_pinpoint_to_sesv2.py --from-pinpoint --region us-east-1 --deploy

This requires pinpoint:ListTemplates and pinpoint:GetEmailTemplate IAM permissions in addition to the Amazon SES permissions listed in Prerequisites.

Handling ses:tags and unsubscribe links

The script provides two optional flags that control how templates are modified during conversion.

Keeping ses:tags for click tracking

Amazon SES supports the ses:tags attribute on HTML <a> tags for link click tracking; because Amazon Pinpoint email sends through Amazon SES, your Pinpoint templates may already contain them. By default, the script strips these attributes because they have no effect without click tracking enabled on your Amazon SES configuration set. If you use Amazon SES click tracking, preserve them:

python3 migrate_pinpoint_to_sesv2.py --local-dir ./templates --keep-ses-tags --deploy

Injecting an Amazon SES-managed unsubscribe link

The --add-unsubscribe-link flag injects an {{amazonSESUnsubscribeUrl}} placeholder before </body> in templates that do not already have one. Amazon SES replaces this placeholder at send time with a link to the Amazon SES subscription management page.

python3 migrate_pinpoint_to_sesv2.py --local-dir ./templates --add-unsubscribe-link --deploy

Use this flag only if you send with ListManagementOptions in the SendEmail request. Sending without ListManagementOptions when the template contains {{amazonSESUnsubscribeUrl}} causes a Rendering Failure.

For a deep dive on unsubscribe compliance, including how to keep your existing unsubscribe page in sync with Amazon SES subscription management, see the Amazon SES subscription management documentation.

Command-line reference

The script accepts the following flags:

Flag Description Default
--region AWS Region us-east-1
--local-dir Directory containing template files (JSON, HTML, HTM) ./sample-templates
--from-pinpoint Fetch templates from Pinpoint API instead of local files Off
--output-dir Directory to save converted Amazon SES JSON files ./output-ses-templates
--dry-run Preview conversions (no files written, no API calls) Off
--deploy Deploy converted templates to Amazon SES v2 Off
--keep-ses-tags Keep ses:tags attributes in HTML for click tracking Off (strip)
--add-unsubscribe-link Inject {{amazonSESUnsubscribeUrl}} link Off
--skip-existing Skip templates that already exist in Amazon SES instead of updating Off (update)
--report FILE Save conversion report as JSON Off

Exit codes

The script returns these exit codes:

Code Meaning
0 All operations completed successfully
1 Partial failure (some templates failed to deploy)
2 Fatal error (missing directory, missing boto3, and so on)

Supported input formats

The script supports these input formats:

Format Extension Processing
Pinpoint JSON .json Must contain TemplateName and TemplateContent with Subject, HtmlPart, TextPart
HTML email .html, .htm Subject extracted from <title> tag, plain text generated from HTML

Cleanup

If you deployed test templates and want to remove them, run the following command:

aws sesv2 delete-email-template --template-name WelcomeEmailTemplate --region us-east-1

To remove the monitoring configuration set and Amazon SNS topic, run the following commands:

aws sesv2 delete-configuration-set --configuration-set-name MigrationMonitoring --region us-east-1
aws sns delete-topic --topic-arn arn:aws:sns:us-east-1:YOUR_ACCOUNT_ID:ses-rendering-failures --region us-east-1

To list all templates in your account, run the following command:

aws sesv2 list-email-templates --region us-east-1

Limitations

Be aware of the following limitations:

  • The script migrates email templates only, not segments, campaigns, or journeys. For engagement feature migration, see Migrating from Amazon Pinpoint.
  • Templates exceeding 500 KB are flagged and skipped. Optimize them (minify HTML, remove redundant CSS, compress image references) before re-running.
  • Placeholder conversion handles Pinpoint’s standard nested paths (User.UserAttributes.*, Attributes.*, User.*). Custom helper functions or conditional logic in templates are not converted.
  • The --add-unsubscribe-link flag injects a generic unsubscribe block. Customize the styling in the script source if needed.

Conclusion

Migrating email templates from Amazon Pinpoint to Amazon SES v2 involves renaming fields, converting placeholder syntax, handling click-tracking attributes, and validating against service limits. The migrate_pinpoint_to_sesv2.py script automates this process, providing dry-run previews, JSON audit reports, and direct deployment to Amazon SES v2. By using the script’s dry-run and reporting capabilities, you can review every conversion before making changes to your AWS account, reducing the risk of errors during migration.

Next steps

To get started, take the following steps:

  • Download the script and run a dry-run against your Pinpoint templates to assess the migration scope.
  • Review the dry-run report for templates with nested placeholders, ses:tags attributes, or size issues.
  • Deploy a pilot batch of templates to Amazon SES and send test emails to verify rendering.
  • Set up Amazon SES subscription management if you need one-click unsubscribe compliance with Gmail and Yahoo.
  • Monitor your Amazon SES sending with Virtual Deliverability Manager after migration.
  • Complete your migration before the October 30, 2026 Pinpoint end of support date.

Related resources

For more information, see the following resources:

About the author

Michael ArabaMichael Araba is a Sr. Technical Account Manager at Amazon Web Services and a member of the Applied AI Communications Technical Field Community (TFC). He works with enterprise customers to remove migration blockers as they transition from Amazon Pinpoint to Amazon SES, AWS End User Messaging, and Amazon Connect. He developed this migration script to help customers automate email template conversion and deployment at scale.