Resend → SendGrid
Move Resend sending to SendGrid by authenticating domains again, rewriting the API client, and copying Resend’s team-wide suppressions onto SendGrid’s bounce, spam, and unsubscribe lists. React Email can keep rendering HTML. SendGrid template IDs are optional. IP reputation stays behind.
Should you make this move?
Both platforms have a case. Compare what you gain with what you give up before scheduling the cutover.
Resend
- A simple API, React Email, and clear domain setup make transactional sending approachable for product teams
- Audience, campaigns, automations, and reporting live in one publishing system
- Message streams, native template languages, and long IP history from older providers do not transfer in
- Automation logic, analytics history, and deliverability settings are not very portable
SendGrid
- High-volume email APIs, templates, marketing tools, dedicated IPs, and a broad ecosystem cover many sending models
- Audience, campaigns, automations, and reporting live in one publishing system
- Account reputation, subusers, suppression scopes, and product complexity require disciplined governance
- Automation logic, analytics history, and deliverability settings are not very portable
SendGrid: High-volume email APIs, templates, marketing tools, dedicated IPs, and a broad ecosystem cover many sending models. This removes a major source-side concern: Message streams, native template languages, and long IP history from older providers do not transfer in.
What you lose: A simple API, React Email, and clear domain setup make transactional sending approachable for product teams. What you inherit: Account reputation, subusers, suppression scopes, and product complexity require disciplined governance.
Jump to a section
Know the shape of the move.
This timeline assumes
- You send through Resend’s API or documented SMTP today.
- You can add SendGrid SPF, DKIM, and optional link-branding records beside Resend DNS until cutover.
- Resend stays able to send until SendGrid completes one production cycle.
- The site already documents SendGrid → Resend and SendGrid → Postmark as nearby routes.
- You export Resend suppressions before the first SendGrid production send.
What survives the move.
“Partial” and “manual” are not footnotes. They are work that must be scheduled and verified.
| Item | Outcome | Impact | What happens | Mitigation |
|---|---|---|---|---|
| Domains and sender identities | manual | critical | SendGrid authenticates domains on Sender Authentication and can also confirm individual sender identities. Resend domains do not transfer. | Complete domain authentication. Send a test from each From address. |
| API payloads | manual | critical | SendGrid uses its own mail send body and personalizations. Resend uses from, to, subject, and html with Bearer auth. | Rewrite the client. Keep HTML output if you already render it. |
| Templates and mail merge | partial | high | SendGrid has native templates and substitutions. Resend’s migrate page says Resend does mail merge with React Email. Those React components do not become SendGrid templates unless you port them. | Keep rendering HTML, or rebuild SendGrid templates and map substitutions. |
| Suppressions | partial | critical | Resend has one team-wide list with bounce, complaint, and manual origins. SendGrid splits bounces, spam reports, blocks, and unsubscribes. A Resend CSV is not a SendGrid import format. | Download Resend’s CSV. Load bounce origins onto Bounces, complaints onto Spam Reports, and unsubscribes you track onto the unsubscribe group you use. |
| Link branding | manual | high | SendGrid click and open tracking can use sendgrid.net unless you add link-branding CNAMEs. | Set link branding if you need on-domain click hosts. Test a live link. |
| Dedicated IPs and rDNS | lost | critical | Resend reputation does not move. SendGrid rDNS is required only when you use dedicated IPs. | Warm the new IP or shared pool. Do not dump full volume on day one. |
| Webhooks | manual | critical | Event names and payloads change. Resend keeps webhook and API request logs. SendGrid Activity is a different store. | Point a staging consumer at SendGrid events first. |
| Inbound | manual | high | SendGrid Inbound Parse is a new MX and MIME post. It does not read Resend receiving webhooks. | Rebuild inbound if you still need it. |
| Idempotency keys | lost | medium | Resend documents Idempotency-Key. SendGrid mail send does not copy that header. | Dedupe in the app. |
| Rate-limit details | partial | medium | Resend documents IETF rate-limit headers. Its SendGrid guide says SendGrid errors without those details. | Update retry logic for SendGrid’s error body. |
| Subusers and EU pinning | manual | high | SendGrid subusers and EU-pinned domains are new structure. Resend multi-region is not a subuser import. | Create only the subusers you need. Authenticate domains per region if you use EU pinning. |
| API request logs | lost | medium | Resend stores API request history. SendGrid’s migrate comparison says SendGrid returns an HTTP response without that log. | Export Resend logs you still need. |
Where each thing goes.
| Source | Destination | Method | Notes |
|---|---|---|---|
| Resend domain | SendGrid authenticated domain | manual | Add SPF and DKIM. |
| RESEND_API_KEY | SENDGRID_API_KEY | manual | Rotate. |
| html and to array | SendGrid content and personalizations | transform | Keep rendered HTML if you can. |
| React Email | HTML content or a SendGrid template | transform | No automatic port. |
| Suppression origin bounce | SendGrid Bounces | transform | Export CSV first. |
| Suppression origin complaint | SendGrid Spam Reports | transform | Do not mail these addresses. |
| Resend webhook | SendGrid event webhook | manual | Map event names. |
| Resend receiving | Inbound Parse, if still required | manual | New MX. |
| Idempotency-Key | No destination | unsupported | Dedupe in the app. |
Make the move recoverable.
Create the source-of-truth backup
Keep Resend keys, suppressions, and DNS so you can send again.
- List domains, From addresses, templates, webhooks, and inbound.
- Download the Resend suppressions CSV.
- Archive React Email or template source.
- Record Resend DNS.
- Keep a Resend key that can still send.
Proof to capture: A manifest lists domains, the CSV hash, and the Resend key owner.
SendGrid client
Replace Resend emails.send with SendGrid mail send.
- Set the SendGrid API key.
- Map from, to, subject, and html onto the SendGrid mail object.
- Drop Idempotency-Key or replace it with your own dedupe.
- Send a canary before you flip production.
Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.
Suppression split
Place Resend’s one list onto SendGrid’s separate lists.
- Split the CSV by origin.
- Load bounces and spam reports.
- Load unsubscribes you still honor.
- Test a known bounce.
Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.
The things most likely to hurt.
These are operating limits. Treat every “Stop if” condition as a blocked migration, not a suggestion.
A Resend bounce never reaches SendGrid Bounces
You imported complaints but not bounces.
- Consequence
- SendGrid mails a mailbox Resend already hard-bounced.
- Mitigation
- Count rows by origin before and after import.
Stop if: A production send goes to an address in the Resend bounce export.
Both keys still send
A worker still has RESEND_API_KEY after SENDGRID_API_KEY is live.
- Consequence
- Duplicate mail.
- Mitigation
- One writer. Disable the old key after the queue drains.
Stop if: A canary gets two copies.
Click hosts surprise you
Links rewrite to sendgrid.net and fail a content check.
- Consequence
- Clicks look untrusted or break.
- Mitigation
- Enable link branding if you need on-domain hosts. Test a click.
Stop if: A production tracked link is wrong.
Do the work in this order.
- Days 1–3 · inventory
Inventory Resend
5–9 hours active2–3 days elapsedOwner review waiting- List domains, send paths, and inbound.
- Decide whether you need subusers or dedicated IPs.
Depends on: Resend and SendGrid admin access
Stop / go checkpointExport?
Go when: Every send path has an owner.
Stop when: A production From address is unknown.
- Days 3–5 · backup
Export suppressions
3–6 hours active1–2 days elapsedCSV download waiting- Download the Resend CSV.
- Archive templates and DNS.
Depends on: inventory
Stop / go checkpointBuild SendGrid?
Go when: The CSV hashes.
Stop when: The export is empty and you know you have bounces.
- Days 5–12 · pilot
Authenticate and rewrite
10–22 hours active5–7 days elapsedDNS and inbox tests waiting- Authenticate the SendGrid domain.
- Rewrite the client.
- Load suppressions on a test subuser.
- Watch events.
Depends on: backup
Stop / go checkpointCut over?
Go when: Canary, skip-on-bounce, and events pass.
Stop when: A required send path still calls Resend.
- Days 12–16 · cutover
Switch senders
3–8 hours active1–3 days elapsedQueue drain waiting- Load production suppressions.
- Point the app at SendGrid.
- Drain Resend jobs.
Depends on: pilot
Stop / go checkpointSendGrid owns sending?
Go when: No Resend production send remains.
Stop when: A duplicate or a suppressed send appears.
- Days 16–18 · observe
Watch deliverability
3–6 hours active3–5 days elapsedInbox signals waiting- Watch bounces and complaints.
- Keep Resend ready.
Depends on: cutover
Stop / go checkpointClose rollback?
Go when: One send cycle is clean.
Stop when: Rates jump.
Cut over with a way back.
Cutover
Make SendGrid the only production sender after Resend suppressions are loaded.
- Split and import the Resend CSV.
- Switch the application to the SendGrid key.
- Drain Resend queues.
- Send canaries.
- Confirm a known bounce is skipped.
Proof to capture: SendGrid sends production mail. Resend is idle. Known bounces are skipped.
Rollback
Return sending to Resend without losing SendGrid-era suppressions you still need.
- Stop SendGrid production sends.
- Restore the Resend key and DNS.
- Export new SendGrid bounces and spam reports.
- Import reviewed rows into Resend.
- Send a canary through Resend.
Proof to capture: Resend is the only production sender again.
- Suppressed address received mail
- Duplicate send
- Webhook consumer failure
- Bounce or complaint spike
- A From address fails authentication
Prove the migration worked.
Every blocking check must pass. Capture the evidence before cleanup begins.
| Pass | ID | Check | Method | Expected result | Evidence |
|---|---|---|---|---|---|
V-01Blocking | SendGrid domain authenticated | Send from each production From address. | SendGrid accepts the message. DKIM aligns. | Sender Authentication page and received header. | |
V-02Blocking | Known bounce is skipped | Send to an address from the Resend bounce export. | SendGrid suppresses the message. | Bounces list and Activity. | |
V-03Blocking | Message shape | Compare a canary with the old Resend payload. | From, To, subject, and html match the approved map. | Request log. | |
V-04Blocking | Event consumer | Trigger delivered and bounce events. | One mapped event each. | Consumer log. | |
V-05Blocking | Click host | Open a tracked link. | The host is the approved SendGrid or branded host. | Link inspect. | |
V-06Blocking | Resend idle | Watch Resend Emails after cutover. | No new production sends. | Emails screenshot. | |
V-07Blocking | No duplicate canary | Retry a send the way production does. | One delivered message. | Inbox. | |
V-08Blocking | Resend still sends | Keep a rollback key and send a staging message. | Resend still accepts mail. | Rollback send. |
Remove the scaffolding safely.
Safe after: One full send cycle, stable rates, and seven days without a rollback trigger.
- Archive the Resend CSV and SendGrid bounce export.
- Revoke the Resend production key.
- Remove Resend DNS after mail no longer uses it.
- Keep Resend readable through the retention window.
- Document the SendGrid key rotation.
- Schedule the next suppression review.
Verify against the primary material.
Platform behavior changes. Check these sources and the review dates above before executing a production migration.
- Resend: migrate from SendGridAccessed 2026-10-31
- SendGrid: download a bounce listAccessed 2026-10-31
- SendGrid: domain authenticationAccessed 2026-10-31
- Resend: email suppressionsAccessed 2026-10-31