Mailgun to AWS SES Migration
Migrating from Mailgun to AWS SES: Step-by-Step Guide
Step-by-step migration guide for engineers moving off Mailgun — pricing breakdown, routing rule equivalents, GDPR-compliant EU region setup, and SNS-based webhook event handling.
Mailgun has long been the go-to for developers who want a clean REST API and minimal operational overhead. AWS SES is where teams land when they prioritize cost efficiency and AWS ecosystem consolidation over out-of-the-box simplicity. If your stack is already on AWS, the migration pays for itself quickly.
## Related Comparisons
Explore other technical comparisons:
- [SendGrid to AWS SES](/compare/sendgrid-to-aws-ses)
- [Postmark to AWS SES](/compare/postmark-to-aws-ses)
## Why Teams Migrate from Mailgun to SES
Cost is the immediate trigger for most migrations. Mailgun's pricing model has shifted over the years — the legacy free tier is gone, and the current Foundation plan carries a meaningful monthly fixed cost.
| Volume | Mailgun Foundation | Mailgun Flex | AWS SES | SES Savings vs Foundation |
| -------------- | -------------------- | ------------- | ------------ | ------------------------- |
| 10,000 emails | $35/month (included) | $8.00/month | $1.00/month | $34.00 |
| 50,000 emails | $35/month (included) | $40.00/month | $5.00/month | $30.00 |
| 100,000 emails | $80/month (overage) | $80.00/month | $10.00/month | $70.00 |
| 500,000 emails | ~$360/month | $400.00/month | $50.00/month | $310.00 |
Mailgun Flex charges $0.80 per 1,000 emails with no monthly minimum — 8x the SES rate. Even the Foundation plan's included 50,000 emails work out to $0.70 per 1,000 against SES's $0.10.
## API Migration: Mailgun → AWS SES
Mailgun's Messages API and SES share the same conceptual model but use different request formats.
| Mailgun API | AWS SES Equivalent | Notes |
| --------------------------------------- | ----------------------------------------------- | --------------------------------- |
| `POST /v3/{domain}/messages` | `SendEmail` / `SendRawEmail` | Core send operation |
| `from`, `to`, `subject`, `text`, `html` | `Source`, `Destination`, `Message` | Direct field mapping |
| API Key (Basic auth) | IAM access key or SES SMTP credentials | Use IAM for AWS-native apps |
| SMTP (smtp.mailgun.org, port 587) | `email-smtp.[region].amazonaws.com`, port 587 | Drop-in SMTP replacement |
| `h:X-Mailgun-*` custom headers | `MessageAttributes` or raw message headers | Same capability, different syntax |
| `o:tag` message tags | Configuration Set tags + SNS message attributes | Equivalent for event filtering |
If your application uses SMTP, the migration is a credentials swap. Update the SMTP host to `email-smtp.us-east-1.amazonaws.com` (or your chosen region), generate SES SMTP credentials from the SES console, and update your application config. No code changes required.
## Routing Rules: Mailgun Routes → SES Receipt Rules
Mailgun Routes allow you to match inbound email by recipient pattern or domain and forward, store, or call a webhook. SES Receipt Rules provide the same capabilities with deeper AWS integration.
**Mailgun route (example):**
```
match_recipient(".*@support.example.com")
→ forward("https://app.example.com/inbound")
→ store(notify="https://app.example.com/stored")
```
**SES Receipt Rule equivalent:**
1. Create a Rule Set in SES Receipt Rules
2. Add a rule matching `@support.example.com`
3. Set actions: Publish to SNS → Lambda function that calls your webhook endpoint
The SNS → Lambda pattern is more verbose to configure but gives you full programmatic control over inbound email routing, parsing, and processing. For teams comfortable with Lambda, it is the more powerful option.
## EU Data Residency: Mailgun EU → SES eu-west-1
Mailgun offers a dedicated EU region (api.eu.mailgun.net) to keep email data within Europe for GDPR compliance. SES supports the same via region selection.
**SES regions for EU data residency:**
- `eu-west-1` (Ireland) — primary EU region, lowest latency to EU users
- `eu-central-1` (Frankfurt) — German data residency if required
- `eu-west-2` (London) — UK data residency post-Brexit
Configure your SES SDK client to use the appropriate regional endpoint. DNS verification records (DKIM CNAME, MAIL FROM MX) must be added for each region separately — you cannot share verification between SES regions.
## Webhook Event Format Mapping
Mailgun fires webhook POSTs to your endpoint for each email event. SES routes events through SNS, which then calls your HTTP endpoint (via SNS HTTP subscription) or Lambda.
| Mailgun Event | SES/SNS Event Type | Key Fields |
| -------------------- | -------------------- | --------------------------------------------------------------------------- |
| `delivered` | `Delivery` | `timestamp`, `recipients[]`, `smtpResponse`, `reportingMTA` |
| `failed` (permanent) | `Bounce` (Hard) | `bounceType: "Permanent"`, `bouncedRecipients[].emailAddress`, `timestamp` |
| `failed` (temporary) | `Bounce` (Soft) | `bounceType: "Transient"`, `bouncedRecipients[].emailAddress`, `timestamp` |
| `complained` | `Complaint` | `complainedRecipients[].emailAddress`, `complaintFeedbackType`, `timestamp` |
| `opened` | `Open` | `timestamp`, `ipAddress`, `userAgent`, `destination` |
| `clicked` | `Click` | `timestamp`, `ipAddress`, `userAgent`, `link` |
| `unsubscribed` | No native equivalent | Must implement via List-Unsubscribe header + custom application handler |
| `stored` | No equivalent | SES does not store messages; use S3 action via Receipt Rules |
**Important:** SES events arrive wrapped in an SNS notification envelope. The `Message` field of the SNS notification contains a JSON string (double-encoded) of the actual SES event. Your Lambda handler must `JSON.parse(event.Records[0].Sns.Message)` to access the SES event object.
## Why Choose FactualMinds for Your Email Migration
FactualMinds is an **AWS Select Tier Consulting Partner** specializing in email infrastructure migration. We have executed SendGrid, Mailgun, Postmark, and SparkPost to AWS SES migrations and know exactly where teams get stuck.
- **Email migration experts** — we handle domain verification, DKIM, bounce architecture, IP warming
- **Assessment-first approach** — we map your current state before writing a line of infrastructure code
- **Zero-downtime cutover planning included** — no failed deliveries during migration
- **AWS Select Tier Partner** — [verified on AWS Partner Network](https://partners.amazonaws.com/partners/001aq000008su2EAAQ/Factual%20Minds)
---Mailgun has long been the go-to for developers who want a clean REST API and minimal operational overhead. AWS SES is where teams land when they prioritize cost efficiency and AWS ecosystem consolidation over out-of-the-box simplicity. If your stack is already on AWS, the migration pays for itself quickly.
Related Comparisons
Explore other technical comparisons:
Why Teams Migrate from Mailgun to SES
Cost is the immediate trigger for most migrations. Mailgun’s pricing model has shifted over the years — the legacy free tier is gone, and the current Foundation plan carries a meaningful monthly fixed cost.
| Volume | Mailgun Foundation | Mailgun Flex | AWS SES | SES Savings vs Foundation |
|---|---|---|---|---|
| 10,000 emails | $35/month (included) | $8.00/month | $1.00/month | $34.00 |
| 50,000 emails | $35/month (included) | $40.00/month | $5.00/month | $30.00 |
| 100,000 emails | $80/month (overage) | $80.00/month | $10.00/month | $70.00 |
| 500,000 emails | ~$360/month | $400.00/month | $50.00/month | $310.00 |
Mailgun Flex charges $0.80 per 1,000 emails with no monthly minimum — 8x the SES rate. Even the Foundation plan’s included 50,000 emails work out to $0.70 per 1,000 against SES’s $0.10.
API Migration: Mailgun → AWS SES
Mailgun’s Messages API and SES share the same conceptual model but use different request formats.
| Mailgun API | AWS SES Equivalent | Notes |
|---|---|---|
POST /v3/{domain}/messages | SendEmail / SendRawEmail | Core send operation |
from, to, subject, text, html | Source, Destination, Message | Direct field mapping |
| API Key (Basic auth) | IAM access key or SES SMTP credentials | Use IAM for AWS-native apps |
| SMTP (smtp.mailgun.org, port 587) | email-smtp.[region].amazonaws.com, port 587 | Drop-in SMTP replacement |
h:X-Mailgun-* custom headers | MessageAttributes or raw message headers | Same capability, different syntax |
o:tag message tags | Configuration Set tags + SNS message attributes | Equivalent for event filtering |
If your application uses SMTP, the migration is a credentials swap. Update the SMTP host to email-smtp.us-east-1.amazonaws.com (or your chosen region), generate SES SMTP credentials from the SES console, and update your application config. No code changes required.
Routing Rules: Mailgun Routes → SES Receipt Rules
Mailgun Routes allow you to match inbound email by recipient pattern or domain and forward, store, or call a webhook. SES Receipt Rules provide the same capabilities with deeper AWS integration.
Mailgun route (example):
match_recipient(".*@support.example.com")
→ forward("https://app.example.com/inbound")
→ store(notify="https://app.example.com/stored")SES Receipt Rule equivalent:
- Create a Rule Set in SES Receipt Rules
- Add a rule matching
@support.example.com - Set actions: Publish to SNS → Lambda function that calls your webhook endpoint
The SNS → Lambda pattern is more verbose to configure but gives you full programmatic control over inbound email routing, parsing, and processing. For teams comfortable with Lambda, it is the more powerful option.
EU Data Residency: Mailgun EU → SES eu-west-1
Mailgun offers a dedicated EU region (api.eu.mailgun.net) to keep email data within Europe for GDPR compliance. SES supports the same via region selection.
SES regions for EU data residency:
eu-west-1(Ireland) — primary EU region, lowest latency to EU userseu-central-1(Frankfurt) — German data residency if requiredeu-west-2(London) — UK data residency post-Brexit
Configure your SES SDK client to use the appropriate regional endpoint. DNS verification records (DKIM CNAME, MAIL FROM MX) must be added for each region separately — you cannot share verification between SES regions.
Webhook Event Format Mapping
Mailgun fires webhook POSTs to your endpoint for each email event. SES routes events through SNS, which then calls your HTTP endpoint (via SNS HTTP subscription) or Lambda.
| Mailgun Event | SES/SNS Event Type | Key Fields |
|---|---|---|
delivered | Delivery | timestamp, recipients[], smtpResponse, reportingMTA |
failed (permanent) | Bounce (Hard) | bounceType: "Permanent", bouncedRecipients[].emailAddress, timestamp |
failed (temporary) | Bounce (Soft) | bounceType: "Transient", bouncedRecipients[].emailAddress, timestamp |
complained | Complaint | complainedRecipients[].emailAddress, complaintFeedbackType, timestamp |
opened | Open | timestamp, ipAddress, userAgent, destination |
clicked | Click | timestamp, ipAddress, userAgent, link |
unsubscribed | No native equivalent | Must implement via List-Unsubscribe header + custom application handler |
stored | No equivalent | SES does not store messages; use S3 action via Receipt Rules |
Important: SES events arrive wrapped in an SNS notification envelope. The Message field of the SNS notification contains a JSON string (double-encoded) of the actual SES event. Your Lambda handler must JSON.parse(event.Records[0].Sns.Message) to access the SES event object.
Why Choose FactualMinds for Your Email Migration
FactualMinds is an AWS Select Tier Consulting Partner specializing in email infrastructure migration. We have executed SendGrid, Mailgun, Postmark, and SparkPost to AWS SES migrations and know exactly where teams get stuck.
- Email migration experts — we handle domain verification, DKIM, bounce architecture, IP warming
- Assessment-first approach — we map your current state before writing a line of infrastructure code
- Zero-downtime cutover planning included — no failed deliveries during migration
- AWS Select Tier Partner — verified on AWS Partner Network
Frequently Asked Questions
How does Mailgun compare to AWS SES?
Can AWS SES receive email like Mailgun?
Is Mailgun or AWS SES better for transactional email?
How do I migrate Mailgun suppression lists to SES?
What is the equivalent of Mailgun routing in AWS SES?
Need Help Migrating to AWS SES?
FactualMinds is an AWS Select Tier Partner specializing in email infrastructure migration. We handle domain verification, Configuration Set architecture, bounce handling, IP warming, and cutover.
