Skip to content

Mailgun

Mailgun is a developer-oriented transactional email service. It is a solid default for Frontmail: a simple API, US and EU regions, detailed event data and webhooks for delivery, bounces, complaints, opens and clicks.

Choose Mailgun when you send transactional mail (sign-ups, receipts, notifications, form submissions) from your own domain, want bounce and complaint tracking, and prefer to keep data in the EU (Mailgun EU region). For a handful of emails from a personal mailbox, SMTP or Gmail is simpler. See the services overview for a comparison.

  • A Mailgun account. New accounts start with a sandbox domain that can only send to authorized recipients (see Sandbox & limits).
  • A sending domain added and verified in Mailgun – we recommend a subdomain such as mg.example.com, so your root domain’s reputation and DNS stay separate.
  • An API key. Create a dedicated key for Frontmail in Account settings → API security → Add new key (older UI: Account → API keys).
    • Use a key with the most restrictive role that can still send and read domain info (e.g. Developer rather than Admin).
    • A domain sending key (Sending → Domain settings → Sending API keys) can send, but cannot read the domain, so Test connection and the daily health check will report it as broken. Use a private account key.
  • Optional: the HTTP webhook signing key from Sending → Webhooks for delivery events.
  1. Open Email services → Add service → Mailgun.
  2. Fill in the fields:
Field Where to find it Example
Region The region shown next to the domain in Mailgun (Sending → Domains) EU (api.eu.mailgun.net)
Sending domain Sending → Domains, exactly as listed mg.example.com
API key Account settings → API security (shown only once when created) key-3ax6… / a1b2c3…-us
Webhook signing key Sending → Webhooks → HTTP webhook signing key 8c1f…
Max emails per second Optional; default 10/s 5
  1. Click Verify & save – Frontmail calls the Mailgun API for the domain and checks that the key, region and domain match.
  2. The service is saved once the check passes. Credentials are encrypted with AWS KMS envelope encryption; only the sender process decrypts them at send time.

The template’s From address must be on the sending domain (e.g. hello@mg.example.com) – or on the root domain if you verified that one.

Mailgun shows the exact records for your domain under Sending → Domains → DNS records. They look like this for mg.example.com:

; SPF
mg.example.com. TXT "v=spf1 include:mailgun.org ~all"
; DKIM – selector is generated per domain (e.g. pic, k1, smtp, mx)
pic._domainkey.mg.example.com. TXT "k=rsa; p=MIGfMA0GCSqGSIb3DQEB…"
; Receiving / bounce handling (recommended)
mg.example.com. MX 10 mxa.mailgun.org.
mg.example.com. MX 10 mxb.mailgun.org. ; EU: mxa.eu.mailgun.org / mxb.eu.mailgun.org
; Open & click tracking
email.mg.example.com. CNAME mailgun.org. ; EU: eu.mailgun.org
; DMARC – on the organizational domain, start with monitoring
_dmarc.example.com. TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.com"
  • Copy the DKIM selector from Mailgun, not from this example – it differs per domain (pic._domainkey, k1._domainkey, …). Newer domains can also use delegated DKIM via CNAME with automatic key rotation.
  • If the root domain already has SPF for your mailbox, that is fine – the subdomain has its own SPF record.
  • Click Verify DNS settings in Mailgun; propagation can take minutes to hours.
  • Once DMARC reports look clean, tighten to p=quarantine and later p=reject.

Mailgun runs two fully separate regions:

Region API host Use when
US api.mailgun.net the domain was created in the US region (default)
EU api.eu.mailgun.net the domain was created in the EU region (data stays in the EU)

A domain exists in exactly one region, so pick the region the domain was created in. A mismatch returns 404 Domain not found, which Frontmail treats as an auth error. The region cannot be changed later – to move, add the domain again in the other region.

  • Sandbox domain (sandbox123….mailgun.org): sends only to authorized recipients (up to 5) that confirmed an invitation email. Anything else fails with “Free accounts are for test purposes only”. Good for a first test, not for production.
  • Free plan: around 100 emails per day.
  • New accounts / domains may be rate-limited by Mailgun until you build sending history or complete business verification.
  • Frontmail’s default rate for Mailgun is 10 messages per second per service; lower it in Max emails per second if Mailgun throttles you.

Mailgun can report what happened after it accepted a message.

  1. Copy the webhook URL from the service page in Frontmail (copy button next to Webhook URL). It looks like:

    https://api.frontmail.dev/webhooks/providers/mailgun/<token>

    <token> is unique to this service – don’t share it between services.

  2. In Mailgun open Sending → Webhooks, choose the right domain (and region), and add the URL for these events:

Mailgun event Frontmail event
Delivered delivered
Permanent failure bounced – the address is added to the suppression list
Temporary failure recorded on the message; Mailgun keeps retrying
Spam complaints complained – added to the suppression list
Opens opened (requires open tracking on the domain)
Clicks clicked (requires click tracking on the domain)
  1. Copy the HTTP webhook signing key from the same page into the service’s Webhook signing key field in Frontmail.

Signature verification: every Mailgun webhook carries timestamp, token and signature. Frontmail computes HMAC-SHA256 of timestamp + token with your signing key and rejects requests whose signature does not match. Without the signing key, events cannot be verified and are ignored.

Frontmail tags every message with v:frontmail_message_id, so events are matched to the right message even when you send the same template many times.

Frontmail sorts provider errors into three classes:

  • auth – the service is broken (invalid API key, 401/403, wrong domain or region, sandbox restrictions). The service is marked unhealthy and the owner gets an email plus a dashboard banner. If the template has a fallback service, the message is sent through it; otherwise the credit is refunded and the message waits in the hold queue as held_service_error, to be sent automatically after you fix the service (re-checked on save and by the daily health check).
  • permanent – this message cannot be sent (invalid recipient, 4xx validation error). The fallback service is tried if configured; otherwise the status is failed and the credit is refunded.
  • transient – timeouts, 5xx, 429 throttling. Retried with exponential backoff; after the retries are exhausted the message is failed and the credit is refunded.
Mailgun response Class What to do
401 Forbidden auth The API key is wrong, deleted or belongs to another account. Create a new key and update the service.
404 Domain not found: mg.example.com auth Check the domain spelling and the Region (EU domains need api.eu.mailgun.net).
400 Domain mg.example.com is not allowed to send: Free accounts are for test purposes only… auth Sandbox domain or unverified account – add an authorized recipient, verify your own domain or upgrade.
403 “account disabled / domain disabled” auth Mailgun suspended sending; check the Mailgun dashboard and contact their support.
400 'to' parameter is not a valid address permanent The recipient address is malformed – see invalid recipient.
413 Request Entity Too Large permanent The message with attachments exceeds Mailgun’s size limit (25 MB).
429 Too Many Requests transient Throttled; Frontmail honours Retry-After. Lower Max emails per second if it happens often.
500 / 502 / 503, timeout transient Mailgun outage – nothing to do, Frontmail retries.
  • Own sending domain (e.g. mg.example.com) added and verified in Mailgun
  • SPF, DKIM, MX and tracking CNAME published; DMARC at least p=none
  • Region in Frontmail matches the domain’s region
  • Private API key with a restricted role, not a domain sending key
  • Test connection passes
  • Webhook URL added for delivered, permanent failure, complaints (+ opens/clicks if needed)
  • Webhook signing key copied into Frontmail
  • From address in the template is on the verified domain