Postmark to AWS SES Migration

Migrating from Postmark to AWS SES: When and How

Postmark is the best deliverability-focused ESP on the market. SES is 5–10x cheaper at high volume. This guide helps you decide whether the cost savings justify the operational trade-offs — and how to execute the migration if they do.

Ask AI: ChatGPT Claude Perplexity Gemini

Postmark is the premium option in transactional email — priced accordingly, and genuinely worth it for teams that prioritize deliverability above all else. AWS SES is a commodity infrastructure service priced at cost. The decision to migrate is fundamentally about whether the cost savings justify building the operational scaffolding that Postmark handles for you.

This guide gives you the honest trade-off analysis and the step-by-step migration path if you decide to move.

The Cost Difference Is Stark

No other comparison in the transactional email space has this wide a price gap at volume.

VolumePostmarkAWS SESMonthly SavingsAnnual Savings
10,000 emails$15/month$1.00/month$14.00$168
50,000 emails$50/month$5.00/month$45.00$540
125,000 emails$100/month$12.50/month$87.50$1,050
500,000 emails~$400/month$50.00/month$350.00$4,200
1,000,000 emails~$800/month$100.00/month$700.00$8,400

SES dedicated IPs ($24.95/IP/month) add some cost, but even with two dedicated IPs, SES is 3–6x cheaper than Postmark at 500K+ emails per month.

Message Streams vs SES Configuration Sets

Postmark’s message streams are its most distinctive feature. Each stream has its own dedicated IP pool, separate bounce/complaint tracking, and isolated reputation. You create a transactional stream and a broadcast (marketing) stream, and Postmark ensures that a complaint spike on your broadcast stream cannot damage your transactional inbox placement.

SES does not have a native message stream concept, but you can replicate the isolation:

Postmark ConceptSES EquivalentSetup Required
Message stream (transactional)Dedicated Configuration Set + IP poolCreate Config Set, request dedicated IPs, assign to transactional sends
Message stream (broadcast)Separate Configuration Set + IP poolSecond Config Set with separate dedicated IPs; enforce separation in app code
Per-stream bounce trackingPer-Configuration-Set SNS event destinationCreate SNS topic per Config Set; subscribe Lambda to aggregate bounce metrics
Per-stream complaint trackingPer-Configuration-Set SNS event destinationSame SNS topic or separate; Lambda processes complaint events per Config Set
Stream-level suppressionAccount-level suppression list + custom storeSES account-level list handles hard bounces; application database for stream-level unsubscribes
Message stream isolationIP pool isolation + Config Set enforcementNo automatic enforcement — application must select correct Config Set per send

API Migration — Postmark → AWS SES

The biggest operational change is moving from Postmark’s HTTP-based API to SES’s SDK calls. Here’s the mapping:

PostmarkAWS SESMigration Notes
POST /emailSendEmail() or SendTemplatedEmail()Postmark accepts JSON; SES uses SDK methods. Use boto3 or AWS SDK for your language.
MessageStream: "transactional"ConfigurationSetName: "transactional"Set this on every SendEmail() call to route to the right IP pool
Template system (Mustache {{var}})No template engineMove rendering to application layer. Use React Email, MJML, or Handlebars in your app. Pre-render the full HTML, send via SES.
Metadata: { key: value }MessageAttributesSES equivalent for custom headers; same pattern for tracking.
Webhook pushes to HTTP endpointSNS topic subscriptionsSES events → SNS → Lambda → your application. More infrastructure but more control.

Key difference: Postmark templates live in Postmark’s UI. SES has no template engine. This forces you to move template logic to your application layer, which is actually cleaner long-term (you control versioning, you can test templates with your code).

Bounce and Complaint Handling

Postmark pushes bounce and complaint webhooks directly to an HTTP endpoint you provide. SES routes these through SNS, requiring a Lambda subscriber.

Architecture:

SES sends email

SES detects bounce or complaint

SES publishes to SNS topic

Lambda is subscribed to SNS topic

Lambda processes event and calls your app (webhook)

Mapping Postmark Webhook Fields to SES:

Postmark Bounce EventSES JSONSES Bounce Type
Type: "Permanent""bounce": { "bounceType": "Permanent" }Hard bounce — recipient address doesn’t exist
Type: "Transient""bounce": { "bounceType": "Transient" }Soft bounce — mailbox full, server temporarily unavailable
Details: { Status: 422 }"bounce": { "bounceSubType": "MailFromDomainNotVerified" }Bounce reason embedded in bounceSubType
Complaint webhook"complaint": { ... }Recipient marked your email as spam (IMPORTANT: add to suppression list immediately)

Lambda Handler Pattern:

exports.handler = async (event) => {
  // SNS wraps the SES event in a Message field
  const message = JSON.parse(event.Records[0].Sns.Message);

  if (message.bounce) {
    console.log(`Hard bounce: ${message.bounce.bounceSubType}`);
    // Update your suppression list
  }

  if (message.complaint) {
    console.log(`Complaint from: ${message.complaint.complainedRecipients}`);
    // Update your suppression list immediately
  }
};

Activity Log Replacement

This is the most painful part of the Postmark → SES transition. Postmark keeps 45 days of searchable email activity — every send, bounce, click, open, complaint — all searchable by recipient, subject, time range, etc.

SES has no equivalent UI. You get SNS events, but no built-in searchable history.

DIY replacement architecture:

  1. SNS → Lambda — capture all SES events (send, bounce, complaint, open, click)
  2. Lambda → DynamoDB — store each event with TTL set to 45 days
  3. DynamoDB Streams → optional OpenSearch — for full-text search on subjects and recipient emails
  4. Query layer — Lambda API to search by email, date range, event type

Estimated effort: 20–30 hours to build; 1–2 hours/month to maintain.

Cost impact: DynamoDB for 45 days of email events:

Bottom line: This is a one-time engineering investment that pays back in 2–3 months versus Postmark’s premium. For teams with engineering capacity, the ROI is clear.

IP Warming Schedule

Moving to dedicated IPs on SES requires warming to establish sender reputation. Follow this conservative schedule to ramp sending volume gradually:

Day RangeDaily Volume CapRationale
Days 1–3200 emails/dayMailbox providers observe sender behavior; start conservatively
Days 4–6500 emails/dayGradual increase; mailbox providers are building reputation profile
Days 7–91,000 emails/dayConsistent sending establishes trust
Days 10–122,000 emails/dayContinue gradual ramp
Days 13–155,000 emails/dayHalfway through warming period
Days 16–1810,000 emails/dayReputation is building; can accelerate
Days 19–2120,000 emails/dayFinal ramping phase
Days 22–2450,000 emails/dayApproaching full volume
Days 25–27100,000 emails/dayNearly at target
Days 28–30Full sending volumeReputation established; send at full capacity

Critical metrics during warming:

If bounce or complaint rates spike, pause the ramp and investigate. A spike at day 15 typically signals a bad list or authentication issue.

Explore other technical comparisons:

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.


Frequently Asked Questions

Is AWS SES as reliable as Postmark?
Postmark has built its entire brand around deliverability and reliability — it maintains separate infrastructure per customer, obsesses over bounce rates, and publishes transparency reports on delivery performance. SES is reliable at AWS infrastructure scale but is a general-purpose service without Postmark's deliverability-first focus. In practice, both platforms achieve comparable inbox placement for transactional email when properly configured with DKIM, SPF, and a warmed sending reputation. Postmark's reputation isolation (message streams) is genuinely better for protecting transactional deliverability from broadcast email impact. For pure transactional email on a clean list, SES delivers comparably. If deliverability is your primary risk, Postmark's premium is defensible.
How do I migrate Postmark templates to AWS SES?
Postmark templates use Mustache-style syntax ({{variable}}) with conditional blocks ({{#if condition}}) and layout inheritance. SES email templates support basic {{variable}} substitution but lack conditional logic and template inheritance. The recommended migration path is to move template rendering to your application layer using a library like React Email, MJML, or Handlebars. Render the full HTML body in your application code, then send the pre-rendered HTML to SES via SendEmail. This decouples your templates from the ESP and works identically whether you are on Postmark, SES, or any other provider.
Does AWS SES have message streams like Postmark?
Not natively, but you can replicate the core benefit using SES Configuration Sets. Postmark message streams isolate transactional and broadcast email into separate IP pools to protect transactional deliverability from broadcast reputation impact. In SES, create separate Configuration Sets — one for transactional, one for broadcast — each pointing to a different dedicated IP pool. This achieves the same reputation isolation. The difference is that Postmark enforces stream separation and gives you per-stream analytics automatically; SES requires you to configure and enforce the separation yourself and aggregate per-Configuration-Set metrics from CloudWatch.
Is Postmark worth the premium over SES?
At low-to-medium volume (under 50,000 emails per month), Postmark's premium is often worth it for the deliverability focus, message stream isolation, and the 45-day message retention with searchable activity logs. The calculus changes at high volume. At 500,000 emails per month, Postmark costs around $400–450 versus $50 on SES — a $350–400 monthly difference. For a 1,000,000 email/month sender, the gap approaches $800/month. At that scale, the engineering cost of building SES event pipelines and log aggregation is typically a one-time investment that pays back in a few months. For teams with AWS expertise, SES wins at scale. For teams without it, Postmark's operational simplicity may be worth more than the monthly cost difference.
What does Postmark charge vs AWS SES?
Postmark charges $15/month for 10,000 emails ($1.50 per 1,000), $50/month for 50,000 emails ($1.00 per 1,000), and $100/month for 125,000 emails ($0.80 per 1,000). AWS SES charges a flat $0.10 per 1,000 emails with no monthly minimum. At 50,000 emails per month, Postmark costs $50 versus $5 on SES — a 10x price difference. At 125,000 emails per month, the ratio is still 8x. Dedicated IPs on SES add $24.95/IP/month, which narrows the gap but does not close it at meaningful volume.

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.