Mailgun vs SendGrid: similar job, different integration surface
All Them APIs
Independent API research
Mailgun and SendGrid expose the same basic job: authenticate, describe a message, submit it, and retain enough evidence to know whether the provider accepted it.
Their APIs make you express that job differently. Mailgun puts the sending domain in the URL, uses HTTP Basic authentication, and accepts multipart form data. SendGrid uses a fixed Mail Send endpoint, Bearer authentication, and a nested JSON document.
That difference is not aesthetic. It changes what a coding agent has to discover, what configuration belongs outside the code, and what a reproducible integration test should assert.
The request shapes optimize for different models
Mailgun's current Send an email reference uses:
POST /v3/{domain_name}/messages;- HTTP Basic authentication with
apias the username and an API key as the password; multipart/form-datafields such asfrom,to,subject,text, andhtml;- US and EU API hosts.
SendGrid's current Mail Send reference uses:
POST /v3/mail/send;- an API key as a Bearer token;
- a JSON body containing
personalizations,from, and one or morecontententries; - global and, for eligible accounts, EU API hosts.
| Integration detail | Mailgun | SendGrid |
|---|---|---|
| Endpoint varies by | Sending domain and region | Region |
| Authentication | HTTP Basic | Bearer token |
| Body encoding | Multipart form data | JSON |
| Recipient shape | to field | Nested personalizations[].to[] |
| Sender prerequisite | Active sending domain | Verified sender identity or authenticated domain |
| Test switch | o:testmode=yes | mail_settings.sandbox_mode.enable=true |
A generated Mailgun integration that hardcodes the domain into source can work and still be poorly designed. The domain is account configuration and should be supplied separately. A generated SendGrid integration can fail before the network call if it flattens the recipient fields instead of constructing personalizations.
These are exactly the mistakes a request-construction test should catch.
Sender setup sits outside the HTTP request
Mailgun requires a sending domain in the endpoint. The agent needs to find the correct domain and choose the matching US or EU host. A valid API key does not repair a wrong domain or region.
SendGrid requires a verified sender identity. Its sender documentation distinguishes single-sender verification from domain authentication. The message's from address must line up with account state.
This is why a benchmark should not classify every 4xx response as "bad API integration." The request may be structurally correct while the account lacks a verified sender. That is a blocked setup state, not the same result as malformed JSON.
It is still important evidence. An engineer choosing a provider needs to know which steps had to be completed before the first send.
Their sandbox switches do not mean the same thing
Mailgun documents o:testmode=yes or true. In test mode, Mailgun accepts the message but does not send it. The provider notes that test-mode messages are charged. Its sending-options documentation also describes a delivered event with a special status for this mode.
SendGrid's Sandbox Mode validates a Mail Send request without delivering it. SendGrid says sandbox requests do not generate Event Webhook or Email Activity events and do not consume credits.
| Test behavior | Mailgun test mode | SendGrid sandbox mode |
|---|---|---|
| Request is validated | Yes | Yes |
| Message reaches recipient | No | No |
| Surrounding event/activity behavior | Test-mode event behavior is documented | No Event Webhook or Email Activity event |
| Usage cost | Charged | No credits consumed |
Calling both mechanisms "sandbox" erases the operational difference. One can exercise event handling; the other intentionally stops before that part of the system.
A report should say which mechanism ran. A green "test passed" badge is not enough.
Acceptance evidence needs provider-specific handling
Mailgun returns a JSON response with a provider message identifier when it accepts the message. SendGrid's Mail Send API commonly acknowledges acceptance with HTTP 202 and exposes message identification through response headers rather than a JSON body shaped like Mailgun's.
An evaluator should normalize those contracts into shared fields without discarding the native evidence:
type SendAcceptance = {
accepted: boolean
httpStatus: number | null
messageId: string | null
providerStatus: string | null
errorClass: string | null
}
The shared record makes comparison possible. The retained raw response makes the comparison auditable.
The evaluator also needs to know when a message ID is genuinely required. Some transactional APIs return only a success flag. Requiring an invented ID would reward fabrication rather than consistency.
What an agent benchmark should test
For Mailgun, we want to see whether the agent:
- finds the official current endpoint;
- keeps the sending domain and region in configuration;
- uses Basic authentication without printing the key;
- constructs multipart form data correctly;
- retains the provider message ID or exact sanitized error.
For SendGrid, we want to see whether it:
- selects Mail Send rather than a legacy authentication path;
- uses a Mail Send-scoped Bearer key;
- constructs nested personalizations and content correctly;
- keeps the sender identity in configuration;
- recognizes HTTP 202 and retains the response message identifier when present.
Both attempts should begin in a clean repository, use the same controlled recipient and exact subject, execute one network request, and preserve failed or blocked outcomes. Neither should receive provider-specific debugging help after the timer starts.
Where this comparison stops
This request-level analysis does not establish inbox placement, throughput, regional latency, template ergonomics, webhook reliability, or total cost. It also does not yet contain our new three-run autonomous benchmark results. Those need controlled accounts and reviewed artifacts before publication.
The narrow conclusion is still useful. Mailgun asks the integration to carry more domain and multipart context. SendGrid asks it to construct a more nested JSON contract and satisfy sender-identity state. Their non-delivery modes exercise different system boundaries.
Choose based on the workflow you need to operate, then verify the choice against the maintained Email API ranking and provider evidence. "Both have an email API" is where the comparison starts, not where it ends.