Migrate from Mailgun

Moving from Mailgun to SendRaven.

Mailgun's mailing lists export as a CSV of address, name, vars and subscribed, and its suppressions (bounces, unsubscribes, complaints) export per domain. Each list is one import; each suppression file is one more with the right status.

The sending API is the other half, and it is a straightforward rename: the same fields, a JSON body instead of a form, and one host.

Export steps checked 6 September 2026 against mailgun.com. Weighing it up? SendRaven vs Mailgun.

Export from Mailgun
  1. Sending → Mailing lists, open the list, and export its members as CSV.
  2. Sending → Suppressions, for the domain you send from. Bounces, Unsubscribes and Complaints each export as CSV. If you send from several domains, do it for each.
  3. Import the list first, then each suppression file with its status.

Compared

What changes when you move from Mailgun.

What changes the architecture or the billSendRavenMailgun
Priced per email sent, never per contactYes One meter. A contact is free.Yes
Transactional, campaigns and automations on one planYes One key, one plan, one dashboard, one suppression list.No marketing is Mailjet, a separate product
The reply is a thread, not a webhookYes Joined on Message-ID to the message it answers.No routes post to a webhook
One query for what is awaiting a replyYes GET /v1/threads?awaiting_reply=trueNo
Per-key daily cap and recipient allowlistYes daily_send_limit and allowed_recipients on the key, checked on every send.Partly domain sending keys; no cap or allowlist
Human approval hold on a keyYes requires_approval drafts the message and waits for a person.No
Unsubscribe cancels queued sends and ends the sequenceYes Two writes: suppress the address, cancel what is scheduled for it.No not documented

From Mailgun's own pricing and documentation, last verified 16 September 2026. A “No” means not offered or not documented on that date. Everything else is on SendRaven vs Mailgun.

What moves

What comes across, and what you rebuild.

In MailgunIn SendRaven
Contactsaddress is the email. name is kept as a custom property rather than split into first and last, because guessing the split is wrong more often than it is right.
subscribedyes or no. no imports as unsubscribed and suppressed for marketing.
varsFree-form JSON per member. Not imported as-is; flatten the keys you want into columns first, and each becomes a property.
BouncesThe per-domain bounces export, imported as "everyone in this file bounced".
UnsubscribesThe per-domain unsubscribes export, imported as "…unsubscribed".
ComplaintsThe per-domain complaints export, imported as "…reported spam".
TemplatesHandlebars HTML, moved into SendRaven templates with {{variables}}.

The file

What the export looks like, and how the import reads it.

The list export: address, name, vars, subscribed. The import maps address to email, name to a property, ignores vars, and reads subscribed as the status.

A suppression export is a list of addresses with a created time and, for bounces, the error code. The file is the status; choose it at import.

The part that matters

Bring the opt-outs.

Mailgun's suppressions are per domain and separate from the lists, so a list export alone brings none of them. Bounces and complaints are the ones that hurt: an address Mailgun refused to mail will bounce again here, and enough of them in the first campaign trips the reputation gate. Import all three files before that campaign.

Templates and sending

The copy and the code.

Mailgun templates are Handlebars. Copy the HTML into a SendRaven template; plain {{variables}} carry over, conditionals and loops do not. Drop the %unsubscribe_url% footer. SendRaven adds the unsubscribe link and the List-Unsubscribe headers to marketing sends itself.

POST /v3/{domain}/messages with form fields becomes POST /v1/emails with a JSON body: from, to, subject, html or text. Recipient variables become a template and per-recipient variables, or a broadcast for a whole list. Add an Idempotency-Key and retries are safe.

# Mailgun
curl -s --user "api:key-..." https://api.mailgun.net/v3/mail.acme.com/messages \
  -F from="Acme <hello@mail.acme.com>" -F to=ana@example.com -F subject="Hi" -F html="<p>Hi</p>"

# SendRaven
curl -X POST https://api.sendraven.ai/v1/emails \
  -H "Authorization: Bearer sk_live_..." \
  -H "Idempotency-Key: hi-ana-1" \
  -d '{ "from": "Acme <hello@mail.acme.com>", "to": "ana@example.com", "subject": "Hi", "html": "<p>Hi</p>" }'

What it costs

Estimate the bill by emails sent, not contacts.

Emails a month
200,000
SendRaven, Standard plan
$85.00 a month
For the 50,000 contacts
$0

On a new sending domain, the first campaign to all 50,000 goes out over 8 days: the warm-up pauses it at each day's ceiling and resumes it at midnight UTC. The ceiling keeps rising for 14 days from the first send, then comes off. Published plan prices, before tax. Transactional mail, if you move it too, counts on the same meter; replies are never metered.

Then, in order

The steps every migration shares.

Verify your domain first

Add the domain under Domains and publish the DNS records it gives you. Use a subdomain you have not sent from before if you can (mail.yourdomain.com for transactional, news.yourdomain.com for campaigns), so the two reputations stay separate. Nothing sends until this is green, and it can take a while for DNS to settle, so start it before the export.

Import the subscribers

Contacts → Import a CSV. Pick or create the list, upload the export, and check the column mapping: address, names, tags, and which columns become custom properties. Re-running the same file is safe: existing contacts are updated, not duplicated.

Import the opt-outs

Then the unsubscribed, bounced and complained lists, with the matching status. Each one is flagged and suppressed before your first send: unsubscribes for marketing only, bounces and complaints for everything. An import never resubscribes someone who has opted out here.

Check the counts

The audience page shows how many were imported, updated and suppressed. Compare the suppressed count to what the old provider reported. If it is far off, the status column was read differently from how you meant. The mapping step shows what each value became.

Switch the API key

For transactional mail, point the code at POST /v1/emails with a SendRaven key. The request shape is from, to, subject, html or text, and an Idempotency-Key header. Keep the old key alive for a day in case something still points at it.

Send the first campaign to the engaged part of the list

A new domain has no history, and mailbox providers judge it on the first few thousand messages. Opens and clicks start from your first SendRaven send, so use the old provider's engagement: tag the recently engaged people on import, send the first campaign to a segment on that tag, then widen. A new sending domain also warms up, so a large first campaign spreads over several days on its own. The reputation gate refuses a campaign once the bounce or complaint rate is already high; it cannot refuse the one that gets you there.

Questions

Asked by people leaving Mailgun.

What happens to the vars on each member?

The import ignores the column, because a JSON blob per row is not a property. Flatten the keys you filter on into their own columns before uploading (plan, signup_date), and each becomes a typed property. The rest can stay behind.

Inbound routes?

SendRaven receives mail on any verified domain and joins replies to the message they answer, without a route per pattern. Set the domain's inbound record and the replies arrive as threads; a webhook fires for each.

Start with the domain.

3,000 emails a month, inbound included, and no charge until you switch paid sending on. Verify the domain today and import the list once the DNS has settled. The other guides are on the migrate page.