Amazon SES migration guide

Migrate from Amazon SES without carrying AWS plumbing

Postscale replaces common SES setups with one email API: REST sending, SMTP relay, inbound webhooks, suppression management, DKIM, warming, and per-domain stats.

Migration scope

  • Replace SendEmail or SendRawEmail with POST /v1/send.
  • Swap SES SMTP credentials for Postscale SMTP relay credentials.
  • Replace S3 plus Lambda receipt rules with inbound webhooks.
  • Move account-level suppressions before production traffic.

What changes when you move

Amazon SESPostscaleMigration note
SendEmail APIPOST /v1/sendMap Source/Destination/Message into from, to, subject, html_body, and text_body.
SMTP interfacePostscale SMTP relayChange host, username, and password while leaving legacy SMTP clients in place.
Receipt rulesInbound rulesUse aliases and rule conditions instead of S3, SNS, and Lambda wiring.
S3 raw MIME storageInbound Email APIPostscale stores parsed inbound messages and attachments without a custom parser.
Account suppression listSuppression APIExport account-level suppressions by reason and import before the first send.

Cut over in controlled steps

1

Mirror DNS

Add Postscale verification, DKIM, return-path, and optional MX records while the old provider keeps sending.

2

Convert code

Swap API credentials and normalize the send payload. Keep the old provider path behind a feature flag for rollback.

3

Move state

Import suppressions and template HTML, then configure delivery, bounce, complaint, and inbound webhooks.

4

Ramp traffic

Start at 10 percent, watch bounces and complaints by ISP, then increase volume as warming limits allow.

Send call conversion

Amazon SES
import { SESv2Client, SendEmailCommand } from "@aws-sdk/client-sesv2";

const ses = new SESv2Client({ region: "eu-central-1" });

await ses.send(new SendEmailCommand({
  FromEmailAddress: "Acme <alerts@example.com>",
  Destination: { ToAddresses: ["user@example.com"] },
  Content: {
    Simple: {
      Subject: { Data: "Welcome" },
      Body: { Html: { Data: "<p>Hello from Acme</p>" } },
    },
  },
}));
Postscale
await fetch("https://api.postscale.io/v1/send", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.POSTSCALE_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    from: "Acme <alerts@example.com>",
    to: ["user@example.com"],
    subject: "Welcome",
    html_body: "<p>Hello from Acme</p>",
  }),
});

Production checklist

Lower DNS TTL to 300 seconds at least 24 hours before cutover.
Keep both DKIM selectors published during the transition.
Import hard bounces, complaints, unsubscribes, and manual suppressions before the first production send.
Run webhook handlers in dual-shape mode until all old-provider events have drained.
Send seed tests to Gmail, Outlook, Yahoo, iCloud, and a corporate Microsoft 365 tenant.
Cut over early in the week and avoid final traffic moves on Friday.
Monitor delivery, bounce, deferred, and complaint rates by ISP after each traffic increase.
Keep the old account active until delayed events and user replies have stopped arriving.

Frequently asked questions

What replaces SES receipt rules?

Postscale inbound aliases and rules replace the common S3/SNS/Lambda chain with signed webhook delivery and stored inbound messages.

Can legacy SMTP systems move first?

Yes. Change SMTP host and credentials to Postscale, then migrate REST sends later.

Do I still need to warm domains?

Yes. Any meaningful sender reputation move should ramp gradually. Postscale warming controls help enforce that ramp by domain and ISP.