Migrate from SendGrid without a rewrite
Postscale covers the SendGrid pieces most product teams depend on: REST sending, SMTP relay, event webhooks, inbound parse, templates, suppressions, and domain authentication.
Migration scope
- Replace SendGrid Mail Send with POST /v1/send.
- Map categories and custom_args to Postscale tags and metadata.
- Replace Inbound Parse with structured inbound email webhooks.
- Keep API and SMTP cutover paths available for rollback.
What changes when you move
| SendGrid | Postscale | Migration note |
|---|---|---|
| Mail Send API | POST /v1/send | Normalize personalizations into to, cc, bcc arrays and move custom_args into metadata. |
| Event Webhook | Postscale webhooks | Subscribe to delivery, bounce, complaint, open, click, and received events per endpoint. |
| Inbound Parse | Inbound Email API | Point MX at Postscale and receive parsed JSON with headers, body, and attachments. |
| Dynamic Templates | Postscale templates | Import HTML and Handlebars variables, then send by template slug or ID. |
| Suppressions | Suppression API | Export bounces, complaints, unsubscribes, and global suppressions separately before import. |
Cut over in controlled steps
Mirror DNS
Add Postscale verification, DKIM, return-path, and optional MX records while the old provider keeps sending.
Convert code
Swap API credentials and normalize the send payload. Keep the old provider path behind a feature flag for rollback.
Move state
Import suppressions and template HTML, then configure delivery, bounce, complaint, and inbound webhooks.
Ramp traffic
Start at 10 percent, watch bounces and complaints by ISP, then increase volume as warming limits allow.
Send call conversion
import sgMail from "@sendgrid/mail";
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
await sgMail.send({
from: "Acme <alerts@example.com>",
to: "user@example.com",
subject: "Welcome",
html: "<p>Hello from Acme</p>",
categories: ["onboarding"],
customArgs: { user_id: "usr_123" },
});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>",
tags: ["onboarding"],
metadata: { user_id: "usr_123" },
}),
});Production checklist
Frequently asked questions
Can SendGrid and Postscale run at the same time?
Yes. Publish both DKIM selectors, keep SendGrid active, and split traffic in your application until Postscale delivery metrics are stable.
What replaces SendGrid Inbound Parse?
Postscale inbound email webhooks receive parsed message metadata, bodies, headers, and attachments after you point MX records at Postscale.
Do I need to rewrite all templates?
No. Keep rendering HTML in your app or import template HTML and variables into Postscale templates.