SendGrid → Resend
Move SendGrid sending to Resend by verifying domains again, rewriting the API client, and importing suppressions. SendGrid templates and mail merge do not land as Resend templates. Use React Email or HTML you already render. Dedicated IPs and warm-up state stay behind.
Should you make this move?
Both platforms have a case. Compare what you gain with what you give up before scheduling the cutover.
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
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
Resend: A simple API, React Email, and clear domain setup make transactional sending approachable for product teams. This removes a major source-side concern: Account reputation, subusers, suppression scopes, and product complexity require disciplined governance.
What you lose: High-volume email APIs, templates, marketing tools, dedicated IPs, and a broad ecosystem cover many sending models. What you inherit: Message streams, native template languages, and long IP history from older providers do not transfer in.
Jump to a section
Know the shape of the move.
This timeline assumes
- Transactional and broadcast traffic from a small set of authenticated domains, not a multi-subuser SendGrid estate.
- You can add DNS records for a new Resend domain without removing SendGrid records until cutover.
- SendGrid stays able to send until Resend has passed one production send cycle.
- The site already documents SendGrid → Postmark if you want Postmark instead of Resend.
- You export SendGrid bounces, spam reports, blocks, and unsubscribes before the first Resend 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 |
|---|---|---|---|---|
| Sending domains | manual | critical | Resend verifies domains on its Domains page. SendGrid domain authentication and sender identities do not move. | Add Resend DNS, wait for verification, and send a test from each From address. |
| SPF, DKIM, and DMARC | manual | critical | New DKIM and SPF records must coexist with SendGrid during dual-send. Link branding CNAMEs that point at sendgrid.net will not brand Resend clicks. | Publish Resend records first. Keep SendGrid records until Resend is the only sender. |
| API payloads and SDKs | manual | critical | Resend uses Authorization: Bearer and snake_case JSON. SendGrid personalizations and template IDs are not Resend fields. | Rewrite one send path, then the rest. Compare From, To, subject, html, and attachments. |
| Templates and mail merge | partial | high | Resend’s SendGrid guide says SendGrid has native mail merge and templates. Resend does that work with React Email, not imported SendGrid templates. | Render HTML in the app or rebuild templates. Do not expect a template-ID swap. |
| Suppressions | partial | critical | SendGrid keeps separate bounce, spam-report, block, and unsubscribe lists. Resend keeps one team-wide list with bounce, complaint, or manual origins. Resend skips a suppressed address on every domain. | Export each SendGrid list. Import the union into Resend with the Suppressions CSV or API before production sends. |
| Webhooks and events | manual | critical | Event names and payloads change. Resend stores webhook delivery logs. SendGrid event webhooks do not replay into Resend. | Map bounce, delivery, complaint, and open events. Point one staging consumer at Resend first. |
| Dedicated IPs and warm-up | lost | critical | IP reputation does not transfer. A sudden volume spike on a new IP or shared pool can look like a new sender. | Warm the new path. Keep SendGrid for leftover volume until inbox placement looks stable. |
| Inbound parse routes | manual | high | SendGrid Inbound Parse MX and the posted MIME payload are not a Resend import. | Rebuild inbound receiving if you still need it. Test the full MIME path. |
| Activity and API logs | lost | medium | SendGrid Activity history stays in SendGrid. Resend’s guide says SendGrid returns an HTTP response and does not keep API request logs. Resend does keep API logs. | Export required SendGrid evidence before you lose access. |
| Subusers and regional pinning | lost | high | SendGrid subusers, EU-pinned domains, and on-behalf-of keys have no Resend equivalent in the migrate guide. | Flatten the sending map. Give each app its own Resend API key. |
| Link branding hosts | manual | high | Click and open tracking hosts change. Old sendgrid.net wrappers will not match Resend. | Update tracked-link expectations and DMARC alignment after the new tracking host is live. |
| Rate-limit behavior | partial | medium | Resend documents IETF rate-limit headers. SendGrid documents an error without those details. | Read Resend headers in the new client. Do not copy SendGrid retry code blindly. |
Where each thing goes.
| Source | Destination | Method | Notes |
|---|---|---|---|
| Authenticated domain | Resend domain | manual | Verify DNS before production From addresses. |
| Sender identity | Any address on a verified Resend domain | transform | Confirm the exact From string. |
| SENDGRID_API_KEY | RESEND_API_KEY Bearer token | manual | Rotate. Do not reuse the SendGrid key. |
| Template ID and substitutions | React Email or pre-rendered html | transform | No template import. |
| Bounce CSV | Resend suppression origin bounce or manual | transform | Import before the first live send. |
| Spam report and unsubscribe lists | Resend suppression origin complaint or manual | transform | Merge lists. Resend is team-wide. |
| Event webhook URL | Resend webhook endpoint | manual | Map event types. |
| Inbound Parse hostname | Resend receiving setup if you still need inbound | manual | MX and payload shape change. |
| Dedicated IP | No destination | unsupported | Reputation does not move. Warm the new path. |
Make the move recoverable.
Create the source-of-truth backup
Keep SendGrid sending, DNS, and suppression evidence you can restore.
- Inventory domains, From addresses, template IDs, webhook URLs, inbound hosts, IPs, and apps.
- Export bounces, spam reports, blocks, and unsubscribes.
- Export or screenshot templates you still need.
- Record current SPF, DKIM, DMARC, and link-branding records.
- Keep a SendGrid API key that can still send until rollback closes.
Proof to capture: A dated manifest lists every domain, suppression file hash, and the SendGrid key owner.
Send client rewrite
Replace the SendGrid SDK call with Resend’s emails.send shape.
- Swap the auth header to Authorization: Bearer.
- Send from, to, subject, and html on one message.
- Render former template IDs in the app or with React Email.
- Add an Idempotency-Key on retries.
Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.
Suppression import
Stop Resend from mailing addresses SendGrid already rejected.
- Export each SendGrid suppression list.
- Dedupe by address.
- Import into Resend before production volume.
- Sample a known bounce and confirm Resend skips it.
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.
You send before suppressions land
Resend accepts a send to an address that is on the SendGrid bounce list.
- Consequence
- You hit a known-bad mailbox and hurt the new domain.
- Mitigation
- Import suppressions and test a known bounce first.
Stop if: A production send goes to an address you already exported as bounced.
Both providers send the same message
A job still has the SendGrid key after the Resend key is live.
- Consequence
- Users get duplicates. Event consumers double-count.
- Mitigation
- One writer per message type. Disable the old key after the last queue drains.
Stop if: The same template is delivered twice to a canary inbox.
DNS still points tracking at SendGrid
Click or open hosts still use sendgrid.net after the API cutover.
- Consequence
- Clicks 404 or attribution breaks.
- Mitigation
- Check a live message’s rewritten links before you raise volume.
Stop if: A production click host is still SendGrid while Resend is sending.
Do the work in this order.
- Days 1–3 · inventory
Inventory SendGrid
6–10 hours active2–3 days elapsedOwner review waiting- List domains, From addresses, templates, webhooks, inbound, and IPs.
- Decide which apps move first.
Depends on: SendGrid and DNS 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 lists and templates
4–8 hours active2 days elapsedCSV downloads waiting- Export every suppression list.
- Archive templates and DNS.
Depends on: inventory
Stop / go checkpointBuild Resend?
Go when: Suppression files hash and counts exist.
Stop when: A list is missing.
- Days 5–12 · pilot
Verify and rewrite
10–22 hours active5–7 days elapsedDNS and inbox tests waiting- Verify the Resend domain.
- Rewrite one send path.
- Import suppressions on a staging team.
- Watch webhook events.
Depends on: backup
Stop / go checkpointCut over?
Go when: Canary inbox, skip-on-bounce, and events pass.
Stop when: A required template still needs a SendGrid template ID.
- Days 12–16 · cutover
Switch senders
3–8 hours active1–3 days elapsedQueue drain waiting- Import production suppressions.
- Point the app at Resend.
- Drain SendGrid queues.
- Raise volume in steps.
Depends on: pilot
Stop / go checkpointResend owns sending?
Go when: No SendGrid 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, complaints, and latency.
- Keep SendGrid ready.
Depends on: cutover
Stop / go checkpointClose rollback?
Go when: One full send cycle is clean.
Stop when: Complaint or bounce rates jump.
Cut over with a way back.
Cutover
Make Resend the only production sender after suppressions and DNS are in place.
- Import the final SendGrid suppression export into Resend.
- Switch the application key and disable new SendGrid sends.
- Drain remaining SendGrid jobs.
- Send canary messages and confirm events.
- Raise volume only after skip-on-suppression works.
Proof to capture: Resend sends production mail. SendGrid is idle. A known bounce is skipped.
Rollback
Return sending to SendGrid without losing Resend-era suppressions you still need.
- Stop Resend production sends.
- Restore the SendGrid key and DNS you kept.
- Export Resend suppressions added after cutover.
- Apply reviewed new suppressions to SendGrid.
- Send a canary through SendGrid.
Proof to capture: SendGrid is the only production sender again.
- Suppressed address received mail
- Duplicate send
- Webhook consumer cannot parse events
- Bounce or complaint spike
- A required From address fails verification
Prove the migration worked.
Every blocking check must pass. Capture the evidence before cleanup begins.
| Pass | ID | Check | Method | Expected result | Evidence |
|---|---|---|---|---|---|
V-01Blocking | Resend domain verified | Send from each production From address. | Resend accepts the message. DKIM aligns. | Domain page and a received header. | |
V-02Blocking | Known bounce is skipped | Send to an address from the SendGrid bounce export. | Resend does not deliver. A suppression record exists. | Suppression row and send log. | |
V-03Blocking | Message shape | Compare a canary with the old SendGrid payload. | From, To, subject, html, and attachments match the approved map. | Request log. | |
V-04Blocking | No leftover template IDs | Search the app for SendGrid template IDs. | Production paths render HTML or React Email. | Code search. | |
V-05Blocking | Event consumer | Trigger delivery, bounce, and complaint on staging. | One event each. No SendGrid schema left. | Consumer log. | |
V-06Blocking | SendGrid idle | Watch SendGrid Activity after cutover. | No new production sends. | Activity screenshot. | |
V-07Blocking | Click host | Open a tracked link from a Resend message. | The host is the approved Resend path, not sendgrid.net. | Link inspect. | |
V-08Blocking | SendGrid still sends | Keep a rollback key and send a staging message. | SendGrid still accepts mail. | Rollback send. |
Remove the scaffolding safely.
Safe after: One full send cycle, stable bounce and complaint rates, and seven days without a rollback trigger.
- Archive suppression CSVs and domain screenshots.
- Revoke the SendGrid production key.
- Remove SendGrid DNS after mail and tracking no longer use it.
- Keep SendGrid readable through the retention window.
- Document the Resend key rotation.
- Schedule the next suppression export review.
When the plan met reality.
First-hand accounts are preferred. Vendor case studies are labeled, and every note below is an editorial paraphrase—follow the link for the full context.
Michael Mikuš describes leaving SendGrid after delayed verification emails. Spotflow compared Mailgun, Mailchimp, AWS SES, Resend, and Postmark, then ran GlockApps spam tests on Resend and Postmark. They put Resend in production. A later test on new seed addresses showed Resend at 94.4% inbox-plus-tabs versus SendGrid at 86.0%, with Resend delivering every message under one minute while seven SendGrid messages took more than five. Average delivery was 1.61 seconds on Resend and 73.83 seconds on SendGrid in that run. They still saw a Gmail delay above four minutes on an earlier Resend template and fixed it by changing the template, not by switching providers again.
- Run the same spam and latency test on the old and new provider with fresh seed addresses before you cut over.
- Treat a Gmail delay as a template and reputation problem. Their first Resend template still sat in Gmail for minutes.
- They chose Resend after measured inbox and latency tests, not after a dashboard tour.
- A later template change cut the remaining Gmail delay. The provider swap was not the last fix.
Resend’s Raycast customer story, told in Raycast’s voice, says the team left SendGrid because broadcasts to large audiences felt cumbersome. They started with waitlist emails for iOS and Windows. That first path took about 30 minutes. They then expanded Resend to marketing mail and investor updates. The writeup is a vendor case study. It does not publish bounce rates, suppression counts, or a full API rewrite log.
- Start with one low-risk send path, the way they used waitlist mail, before you move password resets.
- Read this as a vendor page. Confirm domain verification and suppressions from the official docs, not from the 30-minute claim.
- Raycast describes a small SendGrid-to-Resend pilot, then a wider cutover, not a bulk template import.
- The published win is developer workflow and confidence, not a measured deliverability table.
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
- Resend: email suppressionsAccessed 2026-10-31
- SendGrid: domain authenticationAccessed 2026-10-31