Envello
Mailgun alternative

Switching from Mailgun? Move your transactional email to Envello

A step-by-step guide: DNS setup alongside your existing records, the sending-code swap, a dual-send cutover window, and verification with 90 days of searchable logs on Pro.

Mailgun already has an EU region (api.eu.mailgun.net), so data location alone isn't a reason to move. The API differs in format: Mailgun's messages endpoint is form-encoded with HTTP Basic auth and a domain in the URL; Envello's is JSON with a Bearer token. The mailgun.js SDK narrows the gap.

Before: Mailgun Node SDK
import FormData from "form-data";
import Mailgun from "mailgun.js";

const mg = new Mailgun(FormData).client({
  username: "api",
  key: process.env.MAILGUN_API_KEY,
  url: "https://api.eu.mailgun.net",
});

await mg.messages.create("mg.acme.eu", {
  from: "Acme <[email protected]>",
  to: ["[email protected]"],
  subject: "Welcome",
  html: renderedHtml,
});
After: Envello Node SDK
import { Envello } from "envello";

const envello = new Envello(process.env.ENVELLO_API_KEY);

await envello.emails.send({
  from: "Acme <[email protected]>",
  to: "[email protected]",
  subject: "Welcome",
  html: renderedHtml,
});
Before: Mailgun REST
curl -X POST https://api.eu.mailgun.net/v3/mg.acme.eu/messages \
  --user "api:$MAILGUN_API_KEY" \
  -F from="Acme <[email protected]>" \
  -F to="[email protected]" \
  -F subject="Welcome" \
  -F html="<p>Welcome aboard</p>"
After: Envello REST
curl -X POST https://api.envello.dev/emails \
  -H "Authorization: Bearer $ENVELLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Acme <[email protected]>",
    "to": "[email protected]",
    "subject": "Welcome",
    "html": "<p>Welcome aboard</p>"
  }'
Field mapping

Mailgun fields and their Envello equivalents

MailgunEnvello
Basic auth (api:KEY), domain in the URLAuthorization: Bearer <API key>; the domain comes from the from address
Form fields from, to, subject, html, text, cc, bccThe same names in a JSON body; repeated fields become arrays
h:Reply-Toreply_to
h:X-My-Headerheaders: { "X-My-Header": "..." }
attachment (multipart file)attachments: [{ filename, content (base64), contentType }]
o:deliverytime (RFC 2822)send_at (ISO 8601)
recipient-variables (batch with per-recipient values)POST /emails/batch with each item already personalised
template + t:variablesRender the HTML in your code, then send it as html
o:tag, v: custom variablesNo equivalent yet

Templates and batch personalisation

Mailgun templates support Handlebars logic, and recipient-variables personalise one API call for many recipients. Envello's stored templates do {{variable}} substitution only, and batch sends take fully formed emails. Render each recipient's email in your code and send up to 100 per POST /emails/batch.

Address validation

Mailgun's validation API is a separate product from sending. If you use it, don't drop it silently: Envello's POST /emails/validate checks syntax, MX records and disposable domains on every plan.

Four steps

The migration, end to end

1. Add Envello DNS records alongside your existing Mailgun records

Verify your sending domain in Envello and add the SPF include, DKIM CNAMEs, and the return-path CNAME Envello generates. Keep your existing records in place: both providers can authenticate the same domain at once, which is what makes a safe cutover possible. Only remove the old records after Envello has been the sole sender for a few days.

2. Swap the sending call

Point your outbound path at Envello's SDK. The request shape (from, to, subject, html, text, cc, bcc, reply_to, headers, attachments) mirrors the common transactional-API pattern, so the diff in most codebases is the import line, the client instantiation, and the API key environment variable. Templates rendered client-side (React Email, MJML, plain string) plug straight into the html field.

3. Dual-send during the cutover window

Route a small percentage of traffic to Envello first, or fork production sends so each message goes through both providers to non-critical recipients while you verify. Envello's log search shows every send, bounce, complaint, open, and click for 90 days on Pro (7 days on Free, up to 365 days on Scale) so you can confirm parity before flipping the rest of the traffic.

4. Cut over and retire Mailgun

Once Envello has handled a full week of production traffic without regressions on your key deliverability metrics (bounce rate, complaint rate, delivered rate per domain), route 100% of sends through Envello. Export your Mailgun suppression list and add each address with Envello's POST /suppressions so previously-suppressed recipients stay suppressed. Remove the old DNS records last.

Sending HTML from React components? See the React Email guide for how render() plugs straight into the html field.

FAQ

Migration questions

Can I keep sending through Mailgun while I test Envello?+

Yes. Both providers authenticate the same domain via separate DKIM selectors and their own SPF include, so parallel sending is safe as long as each provider's records are in place. Keep the old records until Envello has been the sole production sender for a few days, then remove them.

What happens to my suppression list?+

Export it from Mailgun and add each address with POST /suppressions (a full-access API key works, one address per request), or one by one in the dashboard. If you skip this step, addresses that Mailgun had marked as bounced or complained can send successfully through Envello on day one and generate the same bounce or complaint again, which harms deliverability. Import first, cut over second.

Do I need to change my webhook consumer?+

Yes, at least the payload shape. Envello's webhooks send delivered, bounced, complained, opened, and clicked events with HMAC-signed payloads; the field names and signature header are documented at envello.dev/docs. If your current consumer branches on your existing provider's specific bounce-subtype taxonomy, decide upfront how each subtype maps to Envello's simpler event set before writing the new handler.

How long does the whole migration take?+

For a codebase with a single central sending path, most teams complete the code change in under an hour. Add DNS propagation (up to 48 hours, usually much less), a dual-send verification window (a few days), and one week of production monitoring before retiring the old provider. Plan for two to three weeks end-to-end, not one afternoon.

Free tool

Check your own GDPR/DPA gaps before you switch

8 questions covering data residency, retention, and subprocessor documentation, the same things a security questionnaire asks.

Run the free checklist →
Ready to migrate?

Start free and migrate at your own pace.