← All playbooks
Transactional email migration

Mailgun → Resend

Verify a Resend domain, point the app at the new API or SMTP host, and decide what to do with Mailgun suppressions. Resend suppressions are team-wide. A Mailgun unsubscribe on one domain is not the same thing.

Typical timeline8–18 business days24–50 hours active work
Statusneeds review
Source profileMailgun complaints API reviewed 2026-11-01
Destination profileResend domain and suppression docs reviewed 2026-11-01
Documentation date
Review window
Evidence4 sources
This route needs review.Use it as a planning baseline, then verify the dated sources and test with representative data before production.
Before you migrate

Should you make this move?

Both platforms have a case. Compare what you gain with what you give up before scheduling the cutover.

Current platform

Mailgun

Reasons to stay
  • Flexible APIs, routing, validation, and regional infrastructure suit engineering-led email systems
  • Audience, campaigns, automations, and reporting live in one publishing system
Reasons to leave
  • Domain configuration, event handling, suppression behavior, and account regions require careful operation
  • Automation logic, analytics history, and deliverability settings are not very portable
New platform

Resend

What gets better
  • 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
What gets worse
  • 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
Best of the move

Resend: A simple API, React Email, and clear domain setup make transactional sending approachable for product teams. This removes a major source-side concern: Domain configuration, event handling, suppression behavior, and account regions require careful operation.

Worst of the move

What you lose: Flexible APIs, routing, validation, and regional infrastructure suit engineering-led email systems. What you inherit: Message streams, native template languages, and long IP history from older providers do not transfer in.

Jump to a section
01At a glance

Know the shape of the move.

Transfer outcome12 features audited
Transfer outcome distributionClean transfer: 0, Partial transfer: 2, Manual rebuild: 8, Not transferred: 2.
Clean0
Partial2
Manual8
Lost2
Mapping route10 of 10 fields have a destination path

This timeline assumes

  • Transactional product mail, plus optional receiving. Marketing broadcasts are in scope only if you already send them from the same domains.
  • The site already documents Mailgun → Postmark and SendGrid → Resend.
  • You control DNS for every domain Mailgun sends from.
  • Mailgun stays able to send until Resend has handled a representative day of mail.
  • You can list bounces, complaints, and unsubscribes per Mailgun domain.
02What transfers

What survives the move.

“Partial” and “manual” are not footnotes. They are work that must be scheduled and verified.

ItemOutcomeImpactWhat happensMitigation
Sending domainsmanualcriticalResend sends only from a domain you verify. You add each subdomain separately. Resend recommends a subdomain such as updates.example.com so transactional reputation stays away from marketing mail.Verify the domain and send a test before you change application code.
DNS coexistencemanualcriticalSPF can include both providers during the move. DKIM is a new record, not a copy of Mailgun's key. Bill Nalen deleted Mailgun's DNS records after Resend verified the domain on four sites in December 2023.Add Resend's records first. Remove Mailgun's include only after you stop sending through Mailgun.
The mg subdomainpartialhighBill Nalen left Mailgun because magic links went out with an mg subdomain, and because the pay-as-you-go plan's route cap blocked more domains. He published a 5-route limit for that plan in 2023. Check your current plan before you treat 5 as today's number.Send from the domain you want users to see. Count inbound routes separately from outbound domains.
API and SMTPmanualcriticalMailgun's form POST is not Resend's JSON API. Bill pointed NextAuth's EMAIL_SERVER at smtp://resend:[email protected]:587. That was his December 2023 setup. Confirm the current SMTP host in Resend's docs before you copy it.Change the provider behind one environment variable so rollback is a config change.
TemplatesmanualhighMailgun templates do not become React Email components. Resend's Navattic case study says an engineer migrated off Mailgun and converted several templates to React Email and Tailwind in a few pull requests.Rebuild the templates you still send. Render one of each to a test inbox.
SuppressionspartialcriticalMailgun's complaint API is per sending domain. The Java client docs say bounces, unsubscribes, and complaints are not an account-wide list. Resend suppressions apply to the whole team, on every domain, for transactional and broadcast mail. Origins are bounce, complaint, and manual.Export each Mailgun domain. Import bounces and complaints. Do not import marketing unsubscribes as Resend suppressions unless you want transactional mail blocked too.
Unsubscribe versus suppressionmanualcriticalA Mailgun unsubscribe often means one list on one domain. A Resend suppression skips every future send to that address until you remove it. Resend's bulk API adds up to 100 addresses per call, and the dashboard accepts a CSV.Keep list unsubscribes in your own audience table if Resend should still send password resets.
Inbound routesmanualhighMailgun routes can parse and forward inbound mail. Resend can receive on a domain you configure, but the route actions do not move.List every route. Recreate receiving only where a product feature still needs it.
WebhooksmanualhighMailgun event names are not Resend's. Resend documents suppression.added, suppression.removed, and email.suppressed in the suppression changelog.Point a new endpoint at Resend and run one bounce and one delivery before cutover.
Region and trackingmanualmediumResend lets you pick a sending region, open and click tracking, enforced TLS, and a custom return-path per domain. Mailgun's US or EU account does not copy those toggles.Set region and tracking on purpose. Leave click tracking off for password mail if that matches today's Mailgun domain.
Dedicated IPslosthighA warmed Mailgun dedicated IP does not transfer. The new domain starts without that history.If you depend on a dedicated IP, ask Resend what they offer before you cut volume over in one day.
LogslostmediumHistorical Mailgun events stay in Mailgun. Resend's log starts when you send through Resend.Export the suppression lists and any event history you still audit.
03Field and feature mapping

Where each thing goes.

SourceDestinationMethodNotes
Sending domainVerified Resend domainmanualOne DNS verification per subdomain.
SPF and DKIMResend DNS recordsmanualAdd before you remove Mailgun.
From addressFrom address on that domaintransformResend sends as any address on a verified domain.
API sendResend email APImanualJSON body, not Mailgun form fields.
SMTPResend SMTPmanualConfirm the current host. Bill used smtp.resend.com:587.
TemplateReact Email or HTMLmanualRewrite.
Bounce or complaintTeam suppressiontransformExport per Mailgun domain. Import as bounce or complaint where you can, otherwise manual.
UnsubscribeAudience state, not always a suppressionmanualA suppression blocks all mail from the team.
Inbound routeResend receivingmanualRecreate only the routes you still need.
WebhookResend webhookmanualNew event names.
04Before you begin

Make the move recoverable.

Backup procedure

Create the source-of-truth backup

Keep Mailgun able to send, and keep a copy of every suppression list.

  1. Export bounces, complaints, and unsubscribes for each sending domain.
  2. Save route definitions and template source.
  3. Record the current SPF and DKIM records.
  4. Send a Resend test from the new domain to a mailbox you control.
  5. Leave Mailgun's DNS in place until that test passes.

Proof to capture: A suppression file per domain, a DNS snapshot, and a Resend test message id.

Transformation · Resend domains and your DNS host

Domain verification

Make Resend a legal sender before the app switch.

  1. Add the domain or subdomain.
  2. Publish the records Resend shows you.
  3. Wait until the dashboard marks it verified.
  4. Send one message to yourself.

Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.

Transformation · Mailgun suppression APIs and Resend suppression CSV or batch API

Suppression import

Block known bad addresses without blocking password resets by accident.

  1. Export each Mailgun domain.
  2. Import bounces and complaints.
  3. Hold unsubscribes in a separate file and decide with the product owner.

Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.

05Handle with care

The things most likely to hurt.

These are operating limits. Treat every “Stop if” condition as a blocked migration, not a suggestion.

Pilot

Unsubscribes become global suppressions

criticalpossible likelihood

A marketing unsubscribe list is uploaded to Resend suppressions.

Consequence
Password resets and receipts to those people are skipped.
Mitigation
Import bounces and complaints only, unless you have written otherwise.

Stop if: The unsubscribe file was included in the suppression import.

Cutover

SPF is stripped early

criticalpossible likelihood

Mailgun's include is removed while Mailgun is still the sender.

Consequence
Mail fails SPF and goes to spam, while the API still says delivered.
Mitigation
Remove Mailgun DNS only after the app no longer calls Mailgun.

Stop if: Production still has a Mailgun API key and the SPF include is gone.

Cutover

Both providers send

highpossible likelihood

A worker and a retry queue still use Mailgun.

Consequence
Users get two messages, or one from the old mg domain.
Mitigation
Switch the provider in one config change and drain the old queue first.

Stop if: A Mailgun log shows a production send after the switch.

06Precise timeline

Do the work in this order.

Estimate forA product sending from a few Mailgun domains, moving outbound mail to Resend
Total elapsed8–18 business days
Active work24–50 hours
BufferAdd time for many domains, inbound routes, or a dedicated IP warm-up.
01
Days 1–3Domains and routes2–3 days
02
Days 3–5Export suppressions1–2 days
03
Days 5–12Verify and rewrite4–8 days
04
Days 12–15Switch the sender1–2 days
05
Days 14–20One sending day3–6 days
  1. Days 1–3 · inventory

    Domains and routes

    4–8 hours active2–3 days elapsedDNS access waiting
    • List domains, from-addresses, templates, routes, and webhooks.
    • Separate bounces, complaints, and unsubscribes.

    Depends on: Mailgun admin and DNS access

    Stop / go checkpoint

    Verify Resend?

    Go when: Every sending domain has an owner and a suppression export plan.

    Stop when: Inbound mail has no replacement and the product still needs it.

  2. Days 3–5 · backup

    Export suppressions

    3–6 hours active1–2 days elapsedAPI pagination waiting
    • Export each domain's lists.
    • Snapshot DNS.

    Depends on: Domain list

    Stop / go checkpoint

    Import suppressions?

    Go when: The three lists are separate files.

    Stop when: Unsubscribes are mixed into the bounce file.

  3. Days 5–12 · pilot

    Verify and rewrite

    10–24 hours active4–8 days elapsedDNS and template review waiting
    • Verify the Resend domain.
    • Import bounces and complaints.
    • Send each template to a test inbox.

    Depends on: Suppression files

    Stop / go checkpoint

    Switch the app?

    Go when: SPF, DKIM, and a test message pass.

    Stop when: A template is still only in Mailgun and production sends it.

  4. Days 12–15 · cutover

    Switch the sender

    3–8 hours active1–2 days elapsedQueue drain waiting
    • Drain Mailgun retries.
    • Point the app at Resend.
    • Watch both logs.

    Depends on: Passed test send

    Stop / go checkpoint

    Leave Mailgun idle?

    Go when: New mail is only in the Resend log.

    Stop when: Mailgun still shows production sends.

  5. Days 14–20 · observe

    One sending day

    3–6 hours active3–6 days elapsedBounces and a password reset waiting
    • Compare bounces with the old rate.
    • Keep Mailgun's DNS until you are ready to remove it.

    Depends on: App switch

    Stop / go checkpoint

    Remove Mailgun DNS?

    Go when: A full day of mail looks normal and rollback is still possible.

    Stop when: Spam placement or missing mail shows up.

07The point of change

Cut over with a way back.

Go live

Cutover

Send production mail through Resend without deleting Mailgun's ability to send.

Recommended window: A low-volume hour, with DNS access still available.

  1. Pause producers and drain the Mailgun queue.
  2. Switch the API key or SMTP URL in one change.
  3. Send a password reset and one template to a test user.
  4. Watch Resend and Mailgun logs for the next hour.
  5. Leave Mailgun DNS in place.

Proof to capture: New messages appear only in Resend. A test message is authenticated. Mailgun is idle, not deleted.

Return to safety

Rollback

Point the app back at Mailgun before its DNS records are removed.

Deadline: Before you delete Mailgun's SPF or DKIM records.

  1. Switch the environment variable back to Mailgun.
  2. Confirm SPF still includes Mailgun.
  3. Send a test through Mailgun.
  4. Leave the Resend domain verified.
  5. Note any messages that went out twice.

Proof to capture: Production mail is leaving through Mailgun again and Resend is not receiving new sends.

Rollback immediately when
  • Test message fails authentication
  • Mailgun still sends after the switch
  • Unsubscribes were imported as suppressions
  • A template renders blank
  • Bounce rate jumps on the first real batch
08Verification report

Prove the migration worked.

Every blocking check must pass. Capture the evidence before cleanup begins.

0%
Interactive report preview0 / 8 checks passed
PassIDCheckMethodExpected resultEvidence
V-01BlockingDomain verifiedRead Resend's domain status and a received message's Authentication-Results.The domain is verified and SPF and DKIM pass.Headers.
V-02BlockingFile splitConfirm the imported file has no unsubscribe-only addresses.Bounces and complaints are in. Unsubscribes are held unless signed.Import file list.
V-03BlockingAPI or SMTPSend one message the way production sends.Resend accepts it and the inbox receives it.Message id.
V-04BlockingEach live templateRender every template to a test inbox.Links, names, and from-addresses match the signed samples.Template checklist.
V-05BlockingOne eventTrigger a delivery and a suppression event.Your endpoint stores both.Webhook log.
V-06BlockingRoutes you keptSend a message to each inbound address you still publish.It arrives in the new receiver, or the address was retired on purpose.Inbound test.
V-07BlockingMailgun idleRead the Mailgun log after the switch.No new production sends.Mailgun log.
V-08BlockingDNS still validCheck that Mailgun's records are still published.A rollback send would still pass SPF.DNS snapshot.
09Post-migration cleanup

Remove the scaffolding safely.

Safe after: A normal sending day, with Mailgun DNS still in place until you explicitly remove it.

  1. Archive suppression exports and the DNS snapshot.
  2. Revoke the temporary Resend key used for the test.
  3. Keep the Mailgun account through the rollback window.
  4. Remove Mailgun's SPF include only after that window.
  5. Delete unused inbound routes.
  6. Review tracking toggles on the transactional subdomain.
10Experiences from the field

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.

First-person accountBill Nalen · Bill Nalen

Bill Nalen pointed ShipFast's Mailgun mail at Resend2023

In December 2023 Bill Nalen replaced Mailgun in the ShipFast template. Magic links showed an mg subdomain, and the pay-as-you-go plan's route cap, which he published as 5, blocked more domains. He set EMAIL_SERVER to an smtp URL on smtp.resend.com port 587 with the API key as the password, verified the domain, and deleted Mailgun's DNS records after Resend's records were in place. He says he did this on four domains in about 15 minutes each. He also wrote that he then had one Resend account per domain, and that Resend only sent mail. Those are his December 2023 notes. Check current domain and receiving docs before you treat them as today's product.

What they recommend
  • Confirm the current SMTP host before you copy the EMAIL_SERVER string from this 2023 post.
  • Add the new DNS records before you delete Mailgun's. He removed the old records in the same sitting.
Worth noticing
  • The published reasons were the mg subdomain and a five-route cap on the plan he was using.
  • One Resend account per domain is a tradeoff he accepted in 2023, not a rule to copy without checking.

Resend's Navattic page says an engineer completed a migration from Mailgun and converted several templates to React Email and Tailwind in a few pull requests. It says the previous template system meant design compromises and time spent on nested tables. No engineer is named. The page gives no send volume, no DNS steps, and no suppression plan. It is Resend's customer story.

What they recommend
  • Budget a template rewrite in the app. The story is about React Email, not a Mailgun template export.
  • Do not read DNS or suppression steps into this page. It does not include them.
Worth noticing
  • This is a vendor case study. The migration detail is a few pull requests for templates.
  • The result they describe is easier template changes, not a measured change in delivery.
Sources and evidence

Verify against the primary material.

Platform behavior changes. Check these sources and the review dates above before executing a production migration.

  1. Resend: verified domainsAccessed 2026-11-01
  2. Resend: email suppressionsAccessed 2026-11-01
  3. Mailgun: complaints APIAccessed 2026-11-01
  4. Bill Nalen: replacing Mailgun with ResendAccessed 2026-11-01