# Switching from Mailgun, form-encoding and all

> Switch from Mailgun and keep your client: the same /v3/:domain/messages call, api:key Basic auth, comma fan-out — plus honest timelines and dated pricing.

Canonical: https://emailfast.dev/alternatives/mailgun

## Keep your client

With `mailgun.js`, the switch is a key and a `url`:

```diff
  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 as `api:<key>`,
  and both encodings Mailgun clients actually use: form-urlencoded and multipart.
- **A comma-separated `to` fans 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`, and `o:deliverytime` carry over** — cc/bcc with display names
  intact, and a future `o:deliverytime` schedules 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-variables` are 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, so `recipient-variables` is 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-Key` header — 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](/features/inbound) 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](https://www.mailgun.com/pricing/), promo and intro discounts excluded — method and corrections via the [claims methodology](/legal/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](/compare/pricing-calculator?sends=50000&contacts=5000),
[250,000](/compare/pricing-calculator?sends=250000&contacts=25000), or
[1,000,000](/compare/pricing-calculator?sends=1000000&contacts=100000).

## 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](/pricing) — 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](/compare/mailgun-alternative).

## Next

- [The step-by-step migration guide](/migrate/mailgun)
- [Also pricing SendGrid](/alternatives/sendgrid) or [Postmark](/alternatives/postmark)?
- [Suspended by your current platform?](/alternatives/suspended) Read that first.
- [Apply for early access](/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](/contact).*

## 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:&lt;key&gt; , both application/x-www-form-urlencoded and multipart/form-data bodies, cc / bcc (display names included) and o:deliverytime scheduling honored, and the familiar { &quot;id&quot;: …, &quot;message&quot;: &quot;Queued. Thank you.&quot; } response. A send carrying an attachment, or recipient-variables , gets a Mailgun-shaped 400 { &quot;message&quot;: … } 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.
