Mailgun Bridge
Drop-in replacement for the Mailgun v3 API — authenticate with HTTP Basic using your wemail API key, keep your existing request structure.
The Mailgun bridge lets you migrate from Mailgun to wemail without changing your integration code. Point your base URL to https://api.wemail.io/bridge/mailgun, use HTTP Basic authentication with api as the username and your wemail API key as the password, and keep the same multipart form-data requests. The bridge translates every call into the wemail pipeline.
API Version & Authentication
| Parameter | Type | Required | Description |
|---|---|---|---|
API Version | v3 | Optional | Matches Mailgun v3 URL structure. |
Auth Method | HTTP Basic | Optional | Username: api, Password: your wemail API key. |
Base URL | URL | Optional | https://api.wemail.io/bridge/mailgun |
Supported Endpoints
| Parameter | Type | Required | Description |
|---|---|---|---|
POST /v3/:domain/messages | Supported | Optional | from, to, cc, bcc, subject, text, html, template, o:tag, o:tracking, o:deliverytime, o:testmode, h: headers, v: variables, recipient-variables, t:variables. |
GET /v3/:domain/events | Supported | Optional | Filter by event, recipient/to, begin/end, limit. Paging URLs included. |
GET /v3/domains | Supported | Optional | List all account domains. |
GET /v3/domains/:domain | Supported | Optional | Domain detail with DNS records. |
GET /v3/:domain/bounces | Supported | Optional | List bounces with limit and paging. |
GET /v3/:domain/complaints | Supported | Optional | List complaints with limit and paging. |
GET /v3/:domain/unsubscribes | Supported | Optional | List unsubscribes with limit and paging. |
Mailgun v3 API Compatibility Matrix
| Parameter | Type | Required | Description |
|---|---|---|---|
Messages — Send | Supported | Optional | Multipart form-data. Attachments consumed but not processed. |
Messages — Send MIME | Not Supported | Optional | — |
Messages — Stored Messages | Not Supported | Optional | — |
Events — Query | Supported | Optional | Filter by event type, recipient, time range. Domain-scoped URL but returns account-wide events. |
Domains — List | Supported | Optional | Returns all account domains with DNS records. |
Domains — Get Detail | Supported | Optional | Returns domain object + sending DNS records. |
Domains — Add/Delete/Verify | Not Supported | Optional | Use wemail console for domain management. |
Domains — Connection/Tracking/DKIM | Not Supported | Optional | — |
Suppressions — Bounces (List) | Supported | Optional | List only. Add/delete individual bounces not supported. |
Suppressions — Bounces (CRUD) | Not Supported | Optional | — |
Suppressions — Complaints (List) | Supported | Optional | List only. |
Suppressions — Complaints (CRUD) | Not Supported | Optional | — |
Suppressions — Unsubscribes (List) | Supported | Optional | List only. |
Suppressions — Unsubscribes (CRUD) | Not Supported | Optional | — |
Routes (Inbound Routing) | Not Supported | Optional | — |
Mailing Lists (CRUD + Members) | Not Supported | Optional | — |
Templates (CRUD + Versions) | Not Supported | Optional | template field supported in send but CRUD not available. |
Stats (Domain/Aggregates) | Not Supported | Optional | — |
Tags (List/Get/Stats/Delete) | Not Supported | Optional | Tags can be set via o:tag but tag management not available. |
IPs (List/Dedicated) | Not Supported | Optional | — |
Email Validation | Not Supported | Optional | Use wemail /v3/validate endpoint instead. |
Webhooks (CRUD) | Not Supported | Optional | Use wemail webhook configuration. |
Subaccounts | Not Supported | Optional | — |
Keys (CRUD) | Not Supported | Optional | Use wemail console. |
Credentials (SMTP) | Not Supported | Optional | — |
Field-Level Compatibility
Detailed breakdown of every request field and response field across all supported endpoints.
POST /:domain/messages — Request Fields
| Parameter | Type | Required | Description |
|---|---|---|---|
from | Supported | Required | Sender address. RFC 5322 format accepted (Name <email>). |
to | Supported | Required | Comma-separated recipients. |
cc | Supported | Optional | Comma-separated CC recipients. |
bcc | Supported | Optional | Comma-separated BCC recipients. |
subject | Supported | Optional | Required unless template is set. |
text | Supported | Optional | Plain-text body. |
html | Supported | Optional | HTML body. |
template | Supported | Optional | wemail template name. |
o:tag | Supported | Optional | Tags (max 10). Multiple o:tag fields allowed. |
o:tracking | Supported | Optional | yes/no — enable/disable all tracking. |
o:tracking-opens | Supported | Optional | yes/no — open tracking. |
o:tracking-clicks | Supported | Optional | yes/no/htmlonly — click tracking. |
o:deliverytime | Supported | Optional | RFC 2822 date for scheduled delivery. |
o:testmode | Supported | Optional | yes — send in test mode. |
o:sending-ip-pool | Supported | Optional | Passed through to wemail pool field. |
h:X-Header | Supported | Optional | Custom headers via h: prefix. |
v:variable | Supported | Optional | Custom variables via v: prefix. Stored as metadata. |
recipient-variables | Supported | Optional | JSON string of per-recipient variables. |
t:variables | Supported | Optional | Template variables as JSON string. |
attachment | Not Supported | Optional | Files consumed by parser but not forwarded. |
inline | Not Supported | Optional | Inline images not supported. |
o:dkim | Not Supported | Optional | Ignored. DKIM handled by wemail. |
o:require-tls | Not Supported | Optional | Ignored. |
o:skip-verification | Not Supported | Optional | Ignored. |
o:time-zone-localize | Not Supported | Optional | Ignored. |
POST /:domain/messages — Response
| Parameter | Type | Required | Description |
|---|---|---|---|
id | Supported | Optional | <message-id@domain> format. |
message | Supported | Optional | "Queued. Thank you." on success. |
GET /:domain/events — Request & Response
| Parameter | Type | Required | Description |
|---|---|---|---|
event (query) | Supported | Optional | Filter: delivered, failed, opened, clicked, complained, accepted, rejected, unsubscribed. |
recipient / to (query) | Supported | Optional | Filter by recipient email. |
begin (query) | Supported | Optional | Unix timestamp start. |
end (query) | Supported | Optional | Unix timestamp end. |
limit (query) | Supported | Optional | Max 300. |
from / subject / message-id / tags (query) | Not Supported | Optional | Accepted but ignored. |
ascending (query) | Not Supported | Optional | Always descending. |
Response: items[].event | Supported | Optional | Mapped event type name. |
Response: items[].timestamp | Supported | Optional | Unix timestamp. |
Response: items[].recipient | Supported | Optional | Recipient email. |
Response: items[].envelope | Supported | Optional | sender, targets, transport. |
Response: items[].message.headers | Supported | Optional | to, from, subject, message-id. |
Response: items[].tags | Supported | Optional | Message tags array. |
Response: items[].user-variables | Supported | Optional | Custom variables from v: fields. |
Response: items[].delivery-status | Supported | Optional | On delivered/failed events: code, message, tls, mx-host. |
Response: items[].geolocation | Supported | Optional | On open/click/unsubscribe: country, region, city. |
Response: items[].client-info | Supported | Optional | On open/click: client-name, client-os, device-type. |
Response: paging | Supported | Optional | next/previous URLs. |
GET /domains & GET /domains/:domain
| Parameter | Type | Required | Description |
|---|---|---|---|
Response: name | Supported | Optional | Domain name. |
Response: state | Supported | Optional | active or unverified. |
Response: type | Hardcoded | Optional | Always custom. |
Response: created_at | Supported | Optional | UTC date string. |
Response: smtp_login | Supported | Optional | postmaster@domain. |
Response: sending_dns_records | Supported | Optional | TXT/CNAME records with valid/invalid status. |
Response: receiving_dns_records | Hardcoded | Optional | Always empty array. |
Response: require_tls | Hardcoded | Optional | Always false. |
Response: wildcard | Hardcoded | Optional | Always false. |
GET /:domain/bounces, complaints, unsubscribes
| Parameter | Type | Required | Description |
|---|---|---|---|
limit (query) | Supported | Optional | Max results per request. |
Response: items[].address | Supported | Optional | Suppressed email address. |
Response: items[].created_at | Supported | Optional | UTC date string. |
Response: items[].code (bounces) | Hardcoded | Optional | Always 550. Actual SMTP code not preserved. |
Response: items[].error (bounces) | Supported | Optional | Bounce reason text. |
Response: items[].tags (unsubscribes) | Hardcoded | Optional | Always ["*"]. |
Response: paging | Supported | Optional | previous/first/next/last URLs. |
Scope | Account-wide | Optional | Domain in URL accepted but suppressions are account-scoped, not domain-scoped. |
SDK Downloads
Download the official Mailgun SDK pre-configured for the wemail bridge. The base URL is already set to https://api.wemail.io/bridge/mailgun — just unzip and use with your wemail API key. Auth uses api as the username and your wemail API key as the password.
| Language | Package | Install | Registry |
|---|---|---|---|
| Node.js | mailgun.js | | npm |
| Python | requests | | PyPI |
| PHP | mailgun/mailgun-php | | Packagist |
| Ruby | mailgun-ruby | | RubyGems |
| Go | mailgun-go | | GitHub |
| Java | mailgun-java | | Maven |
| C# | RestSharp | | NuGet |
Known Deviations from Mailgun API
Events scope — The events endpoint returns account-wide events despite the domain in the URL path.
Bounce code — The bounce code field is always 550, not the actual SMTP response code from the remote server.
Attachments — Attachments are consumed by the multipart parser but not forwarded to the recipient. Messages are sent without them.
Auto-creation — The bridge account is automatically created on the first authenticated request. No setup step is required.
Migrating for good? Follow the Mailgun migration guide — templates and suppressions auto-import, and Mailgun stays warm for 30 days.
Code examples
curl -X POST https://api.wemail.io/bridge/mailgun/v3/yourdomain.com/messages \
-u "api:afn_live_YOUR_KEY" \
-F from="sender@yourdomain.com" \
-F to="user@example.com" \
-F subject="Hello from wemail" \
-F html="<p>Hello World</p>"// Official SDK: npm i mailgun.js form-data
const formData = require('form-data');
const Mailgun = require('mailgun.js');
const mailgun = new Mailgun(formData);
// Point the official Mailgun SDK at the wemail bridge
const mg = mailgun.client({
username: 'api',
key: 'afn_live_YOUR_KEY',
url: 'https://api.wemail.io/bridge/mailgun',
});
const res = await mg.messages.create('yourdomain.com', {
from: 'Sender <sender@yourdomain.com>',
to: ['user@example.com'],
subject: 'Hello from wemail',
html: '<p>Hello World</p>',
});
console.log(res); // { id, message: "Queued. Thank you." }import requests
response = requests.post(
"https://api.wemail.io/bridge/mailgun/v3/yourdomain.com/messages",
auth=("api", "afn_live_YOUR_KEY"),
data={
"from": "sender@yourdomain.com",
"to": "user@example.com",
"subject": "Hello from wemail",
"html": "<p>Hello World</p>",
},
)
print(response.json())
# {"id": "<msg-id@yourdomain.com>", "message": "Queued. Thank you."}<?php
// Official SDK: composer require mailgun/mailgun-php
use Mailgun\Mailgun;
// Point the official Mailgun SDK at the wemail bridge
$mg = Mailgun::create('afn_live_YOUR_KEY', 'https://api.wemail.io/bridge/mailgun');
$mg->messages()->send('yourdomain.com', [
'from' => 'Sender <sender@yourdomain.com>',
'to' => 'user@example.com',
'subject' => 'Hello from wemail',
'html' => '<p>Hello World</p>',
]);# Official SDK: gem install mailgun-ruby
require 'mailgun-ruby'
# Point the official Mailgun SDK at the wemail bridge
mg = Mailgun::Client.new('afn_live_YOUR_KEY', 'api.wemail.io/bridge/mailgun')
mg.send_message('yourdomain.com', {
from: 'Sender <sender@yourdomain.com>',
to: 'user@example.com',
subject: 'Hello from wemail',
html: '<p>Hello World</p>'
})// Official SDK: go get github.com/mailgun/mailgun-go/v4
package main
import (
"context"
"fmt"
"github.com/mailgun/mailgun-go/v4"
)
func main() {
mg := mailgun.NewMailgun("yourdomain.com", "afn_live_YOUR_KEY")
// Point the official Mailgun SDK at the wemail bridge
mg.SetAPIBase("https://api.wemail.io/bridge/mailgun/v3")
m := mg.NewMessage(
"Sender <sender@yourdomain.com>",
"Hello from wemail",
"", // plain-text body
"user@example.com",
)
m.SetHtml("<p>Hello World</p>")
_, id, err := mg.Send(context.Background(), m)
if err != nil {
panic(err)
}
fmt.Println(id)
}// Official SDK: com.mailgun:mailgun-java
import com.mailgun.api.v3.MailgunMessagesApi;
import com.mailgun.client.MailgunClient;
import com.mailgun.model.message.Message;
import com.mailgun.model.message.MessageResponse;
public class MailgunBridge {
public static void main(String[] args) {
// Point the official Mailgun SDK at the wemail bridge
MailgunMessagesApi api = MailgunClient
.config("https://api.wemail.io/bridge/mailgun", "afn_live_YOUR_KEY")
.createApi(MailgunMessagesApi.class);
Message message = Message.builder()
.from("Sender <sender@yourdomain.com>")
.to("user@example.com")
.subject("Hello from wemail")
.html("<p>Hello World</p>")
.build();
MessageResponse response = api.sendMessage("yourdomain.com", message);
System.out.println(response.getId());
}
}// Mailgun's documented C# uses RestSharp: dotnet add package RestSharp
using RestSharp;
using RestSharp.Authenticators;
// Point at the wemail bridge
var client = new RestClient("https://api.wemail.io/bridge/mailgun/v3")
{
Authenticator = new HttpBasicAuthenticator("api", "afn_live_YOUR_KEY")
};
var request = new RestRequest("yourdomain.com/messages", Method.Post);
request.AddParameter("from", "Sender <sender@yourdomain.com>");
request.AddParameter("to", "user@example.com");
request.AddParameter("subject", "Hello from wemail");
request.AddParameter("html", "<p>Hello World</p>");
var response = await client.ExecuteAsync(request);
Console.WriteLine(response.Content);{
"id": "<msg-id@yourdomain.com>",
"message": "Queued. Thank you."
}