Switching from Mailgun, form-encoding and all
Mailgun integrations are wire-level habits — Basic auth as api:key, form-encoded bodies, a comma-separated to. All three work here unchanged. What that covers, what it doesn't, and what Mailgun still does better.
Facts verified 2026-08-29 — corrections: hello@emailfast.dev
Keep your client
With mailgun.js, the switch is a key and a url:
import formData from "form-data";
import Mailgun from "mailgun.js";
const mg = new Mailgun(formData).client({
username: "api",
- key: process.env.MAILGUN_API_KEY,
+ key: process.env.EMAILFAST_API_KEY, // ef_sandbox_… works everywhere
+ url: "https://api.emailfast.dev",
});That works because SendGrid-, Mailgun-, and Postmark-compatible endpoints: point your existing SDK at a new base URL with a new key and keep your code — attachment sends are the one exception, refused with a clear error in your provider's own format rather than silently dropped. What the Mailgun-compatible endpoint honors, verified against the code that serves it:
POST /v3/:domain/messages, same shape — HTTP Basic auth asapi:<key>, and both encodings Mailgun clients actually use: form-urlencoded and multipart.- A comma-separated
tofans out to one message per recipient in either encoding. A policy block on any recipient rolls back the whole call with a truthful error — nothing half-queued. cc,bcc, ando:deliverytimecarry over — cc/bcc with display names intact, and a futureo:deliverytimeschedules the send instead of being silently ignored.- The response is Mailgun-shaped:
{ "id": "<…@yourdomain.com>", "message": "Queued. Thank you." }, so response-parsing code keeps working. - Attachments and
recipient-variablesare refused loudly. Outbound attachments aren't supported yet, platform-wide — a send carrying one, as a form field or a multipart file part, gets a Mailgun-shaped 400 saying so, never a message quietly sent without its file. Per-recipient%recipient.x%substitution has no equivalent here, sorecipient-variablesis refused too rather than half-honored. Mailgun-only toggles (o:dkim,o:testmode, tracking overrides, and the like) are accepted without effect; native platform policy applies. - Retries can be made safe with an
Idempotency-Keyheader — each recipient in a fan-out gets its own derived key: a 202 from the API means the send is committed to a durable, partitioned outbox before we answer — a crash can't lose it, and a retry with the same idempotency key can't double-send.
However it arrives, every message passes the same checkpoint: every send — REST, SMTP, browser SDK, compatibility endpoints, broadcasts, automations — passes through one admission gate: idempotency, suppression, quota, and content policy in a single checkpoint no ingress can skip.
How long it actually takes
| What you're moving | The work | Time |
|---|---|---|
Outbound sends (mailgun.js or raw HTTP) | Key + base URL, then a sandbox test | Under an hour |
| Domain verification | SPF/DKIM records at your DNS host | Minutes of work, propagation up to a few hours |
| Stored templates | Re-create today under your old template names (a hosted importer is planned) | An afternoon for a handful |
| Suppression lists | CSV export → suppression import here, before your first send | Under an hour |
| Inbound routes | Rebuild against inbound receiving and test in sandbox | A day or more — prototype this first |
Everything above can run dry before production moves: sandbox keys (ef_sandbox_…) that run the real pipeline dry: real validation, real rendering, real events, a hosted capture inbox — and no email leaves.
What Mailgun publishes at your volume
| Monthly emails | Price / month | Published as |
|---|---|---|
| 10,000 | $15 | Basic (10k included) |
| 50,000 | $35 | Foundation (50k included) |
| 100,000 | $75 | Foundation (100k included; Scale same volume is $90) |
| 250,000 | $215 | Scale (250k included) |
| 500,000 | $400 | Scale (500k included) |
| 1,000,000 | $700 | Scale (1M included) |
Detail: Free plan: 100 emails/day. Volume selector on the pricing page repriced live: Basic $15 (10k incl.), Foundation $35 (50k incl.) / $75 (100k incl.), Scale $90 (100k) / $215 (250k) / $400 (500k) / $550 (750k) / $700 (1M). Foundation and Scale are 'free for 1 month' trials. Overages: from $1.80/1,000 (Basic), $1.30/1,000 (Foundation), $1.10/1,000 (Scale). Dedicated IP $59/mo. 2.5M+ = talk to sales. Prices shown are monthly billing in USD.
Figures verified 2026-08-29 on the Mailgun (Sinch) pricing page, promo and intro discounts excluded — method and corrections via the claims methodology.
Mailgun's mid-to-high-volume pricing is genuinely aggressive — check it against your real numbers rather than taking this page's word: 50,000 sends/month, 250,000, or 1,000,000.
Where Email Fast stands
| Plan | Price / month | Emails included | Overage per 1,000 |
|---|---|---|---|
| Free | $0 | 2,500 | — |
| Starter | $9.90 | 20,000 | $0.90 |
| Creator | $39 | 100,000 | $0.65 |
| Growth | $79 | 300,000 | $0.55 |
| Scale | $249 | 1,500,000 | $0.35 |
Our stake, declared: we make Email Fast, and these are the launch prices already published on our pricing page — during early access they may be refined before general availability, and self-serve checkout opens at GA. Contacts and subscribers are never billed, at any list size.
Where Mailgun wins
From our own pricing survey, their side stated plainly — Developer-first API with best-in-class inbound parsing/routing, strong email validation product, and aggressive per-volume pricing at mid-to-high send volumes.
Honest additions: if inbound parsing is the core of your product, Mailgun set the bar and you should hold us to it in a sandbox test before switching anything. And their email validation is a mature standalone product. The full comparison: Mailgun vs Email Fast.
Next
- The step-by-step migration guide
- Also pricing SendGrid or Postmark?
- Suspended by your current platform? Read that first.
- Apply for early access — live sending starts by application
Mailgun is a trademark of its owner; Email Fast is not affiliated with or endorsed by them. Mailgun facts were verified on their public pages on the dates shown — corrections: hello@emailfast.dev.
Questions, answered plainly
Does my Mailgun client keep working?
Yes: SendGrid-, Mailgun-, and Postmark-compatible endpoints: point your existing SDK at a new base URL with a new key and keep your code — attachment sends are the one exception, refused with a clear error in your provider's own format rather than silently dropped. POST /v3/:domain/messages keeps its shape — HTTP Basic auth as api:<key>, both application/x-www-form-urlencoded and multipart/form-data bodies, cc/bcc (display names included) and o:deliverytime scheduling honored, and the familiar { "id": …, "message": "Queued. Thank you." } response. A send carrying an attachment, or recipient-variables, gets a Mailgun-shaped 400 { "message": … } saying so.
Does a comma-separated `to` still fan out?
Yes — one message per recipient, in both body encodings. And if any recipient in the batch is blocked by policy, the whole call rolls back with a truthful error instead of half-queueing, so a client retry can never double-send the recipients that were clean.
What about my inbound routes?
Rebuild, don't assume. Mailgun's inbound parsing and routing is genuinely best-in-class — it's the first thing to prototype here before you commit. Email Fast has inbound receiving, but if routes are the heart of your integration, test that path in the sandbox before moving outbound sending.
How long does the switch take?
Outbound send calls: under an hour — the change is a key and a base URL, then a sandbox test. Domain verification adds DNS propagation time. Stored templates are re-created today — give each the same slug as its old Mailgun template name and existing template sends work unchanged; a hosted importer is planned — and inbound routes are a rebuild-and-test job, not a flag flip.