Migrate › Mailgun

Move from Mailgun to Relayly

For Mailgun veterans tired of dashboard archaeology. Mailgun's API is straightforward and so is the migration — most teams complete it in an afternoon.

Why teams leave Mailgun

What carries across

Mailgun conceptRelayly equivalentAuto-migrates?
Mailing ListslistsYes — full export with member counts and access levels.
Members (subscribers)list_membersYes — including custom variables.
Suppressions (bounces, unsubs, complaints)SuppressionsYes — full per-domain export.
Domains + DKIM keysdomainsManual re-verify (DKIM keys can't cross providers).
Routes (inbound)Inbound routesPattern-matching translates 1:1. Action handlers may need adjustment.
Templates (Mustache)Liquid templatesAuto-translation handles the common cases. Complex helpers flagged.
Stats / analyticsRead-only archiveOptional. Last 30/60/90 days as analytics-only metadata.
WebhooksWebhooksSame event names; signature header changes. Adapter is 4 lines.

The codebase swap

API shapes are similar enough that find/replace handles most call sites. The key differences:

// Mailgun.js
import formData from "form-data";
import Mailgun from "mailgun.js";
const mg = new Mailgun(formData).client({
  username: "api",
  key: process.env.MAILGUN_API_KEY,
});

await mg.messages.create("yourdomain.com", {
  from:    "hello@yourdomain.com",
  to:      ["user@example.com"],
  subject: "Welcome",
  html:    "<p>Hi</p>",
});
// Relayly Node SDK
import Relayly from "@relayly/node";
const r = new Relayly({ apiKey: process.env.RELAYLY_API_KEY });

await r.email.send({
  from:    { email: "hello@yourdomain.com" },
  to:      [{ email: "user@example.com" }],
  subject: "Welcome",
  html:    "<p>Hi</p>",
});

Inbound routes — direct port

Mailgun routes are a strength of the product, and Relayly inbound routes preserve the model directly. Pattern matching uses similar regex syntax (we expose match_recipient(".*@inbound.example.com"), identical to Mailgun's match_recipient).

The action side is where you'll spend 5-10 minutes per route. Mailgun's forward(...) action becomes a Relayly forwarding rule. store() + later retrieval becomes a webhook to your endpoint with the parsed mail.

The cutover playbook

  1. Run the export script. It's read-only against Mailgun and re-runnable.
  2. Review the manifest. Anything flagged as "needs review" gets a copy-paste remediation snippet.
  3. Apply to Relayly. Idempotent SQL + REST imports. Re-run safely.
  4. Dual-send for a week. Compare inbox rates at Gmail / O365 / Yahoo through the dashboard.
  5. Flip the API key. Search-and-replace your codebase, deploy, monitor 24h.
  6. Pause Mailgun. Don't delete the account — keep it for 30 days as an unsubscribe-list reciprocity reference.
  7. After 30 quiet days, terminate Mailgun. You're done.

Pricing-side check

VolumeMailgunRelaylyAnnual delta
5k sends/mo, no IP$0 (Foundation Free, sunset)$0 (Free, permanent)Free vs trial
50k sends/mo, no IP$35/mo$25/mo+ $120/year
50k sends/mo, with IP$94/mo$25/mo (IP included)+ $828/year
500k sends/mo, with IP$235/mo$100/mo+ $1,620/year

Mailgun pricing as of 2026-05 from mailgun.com/pricing. Mailgun's free Foundation tier was sunset in 2024; trial-only now.

Start the migration

Sign up free, run the export script, dual-send for a week. We'll spot you 10,000 verification sends.

Start free