All posts
Guide·Jul 5, 2026·9 min read

Mailgun API guide: sending, receiving, and validation explained

How the Mailgun API works: authentication, sending with the messages endpoint, inbound routes, the email validation API, and where Mailgun fits vs alternatives.

Dvir Atias

Dvir Atias

Founder

Mailgun is one of the longest-running developer email services: an HTTP API for sending, receiving (via Routes), tracking, and validating email. This guide covers the API surface you'll actually touch - authentication, the messages endpoint, inbound routing, and the validation API - plus the honest limits to know before you commit.

Authentication and regions

Every Mailgun API request uses HTTP Basic auth with the literal username api and your API key as the password. Mailgun runs two regions with different base URLs - US (https://api.mailgun.net) and EU (https://api.eu.mailgun.net) - and a domain created in one region does not exist in the other. The classic first-day bug is a 401 from pointing US keys at the EU endpoint or vice versa.

curl -s --user "api:YOUR_API_KEY" \
  https://api.mailgun.net/v4/domains

Sending with the messages endpoint

Sending is a form-encoded POST to /v3/{domain}/messages:

curl -s --user "api:YOUR_API_KEY" \
  https://api.mailgun.net/v3/mg.yourdomain.com/messages \
  -F from="App <app@mg.yourdomain.com>" \
  -F to="user@example.com" \
  -F subject="Hello from Mailgun" \
  -F text="Plain text body" \
  -F html="<p>HTML body</p>"

Useful, less-known parameters:

  • o:testmode=yes - accepts the message but doesn't deliver it (still charged as an event, great for CI).
  • o:deliverytime - schedule delivery up to a few days ahead.
  • o:tag - up to three tags per message for analytics segmentation.
  • recipient-variables - per-recipient template substitution for batch sends to up to 1,000 recipients per call.

In Node.js, the official mailgun.js client wraps the same call:

import FormData from "form-data";
import Mailgun from "mailgun.js";

const mg = new Mailgun(FormData).client({
  username: "api",
  key: process.env.MAILGUN_API_KEY,
});

await mg.messages.create("mg.yourdomain.com", {
  from: "App <app@mg.yourdomain.com>",
  to: ["user@example.com"],
  subject: "Hello",
  text: "Plain text body",
});

Receiving email: Routes

Mailgun can receive mail for your domain and forward it to your server - configured through Routes: priority-ordered filter expressions (match_recipient("support@.*")) with actions like forward("https://yourapp.com/inbound") and store(). Mailgun POSTs the parsed message (fields for sender, subject, body-plain, attachments) to your endpoint.

It works, but the developer experience shows its age: routes are managed as expression strings, storage is temporary (retrieve within 3 days), and each inbound address is something you wire up rather than something you create as a first-class object. If inbound is the center of your product - agents replying to email, per-customer addresses created at runtime - compare that model with a dedicated inbound-first email API before building on Routes. We dissected Mailgun's inbound webhooks in detail in the Mailgun webhook guide.

The Mailgun email validation API

Mailgun also sells a standalone validation product (v4): syntax checks, DNS/MX verification, disposable-address detection, role-address detection (postmaster@, info@), and a risk rating:

curl -s --user "api:YOUR_API_KEY" \
  -G https://api.mailgun.net/v4/address/validate \
  --data-urlencode address=someone@example.com
{
  "address": "someone@example.com",
  "is_disposable_address": false,
  "is_role_address": false,
  "result": "deliverable",
  "risk": "low"
}

Validation is billed separately from sending, per verification. If you're comparing providers on this feature, our email validation API comparison covers the accuracy/pricing trade-offs across vendors.

Webhooks for delivery events

Mailgun signs delivery-event webhooks (delivered, opened, clicked, failed) with an HMAC of timestamp + token using your signing key - verify it before trusting payloads. Full verification code lives in our Mailgun webhook guide.

Where Mailgun fits - and where it doesn't

Mailgun remains a solid choice for high-volume transactional and marketing sending with mature deliverability tooling. The places to look elsewhere:

  • Inbound-first products. Routes bolt receiving onto a sender. If every user or agent in your product needs its own working address with parsed JSON messages and instant webhooks, an inbox-native API is dramatically less plumbing.
  • AI agents. Agents need to hold conversations: reply threading, reading history, reacting in real time, attachments as data. That's the gap AgenticEmail is built for - POST /v1/inboxes creates a real address; inbound arrives parsed over signed webhooks or WebSocket; a hosted MCP server exposes it all as agent tools.
curl -X POST https://api.agenticemail.dev/v1/inboxes \
  -H "Authorization: Bearer am_..." \
  -d '{"username": "support-agent"}'

See how the pieces compare in the 5 best email APIs for developers, or go straight to the quickstart.

Talk to a real person