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

ParameterTypeRequiredDescription
API Versionv3OptionalMatches Mailgun v3 URL structure.
Auth MethodHTTP BasicOptionalUsername: api, Password: your wemail API key.
Base URLURLOptionalhttps://api.wemail.io/bridge/mailgun

Supported Endpoints

ParameterTypeRequiredDescription
POST /v3/:domain/messagesSupportedOptionalfrom, 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/eventsSupportedOptionalFilter by event, recipient/to, begin/end, limit. Paging URLs included.
GET /v3/domainsSupportedOptionalList all account domains.
GET /v3/domains/:domainSupportedOptionalDomain detail with DNS records.
GET /v3/:domain/bouncesSupportedOptionalList bounces with limit and paging.
GET /v3/:domain/complaintsSupportedOptionalList complaints with limit and paging.
GET /v3/:domain/unsubscribesSupportedOptionalList unsubscribes with limit and paging.

Mailgun v3 API Compatibility Matrix

ParameterTypeRequiredDescription
Messages — SendSupportedOptionalMultipart form-data. Attachments consumed but not processed.
Messages — Send MIMENot SupportedOptional
Messages — Stored MessagesNot SupportedOptional
Events — QuerySupportedOptionalFilter by event type, recipient, time range. Domain-scoped URL but returns account-wide events.
Domains — ListSupportedOptionalReturns all account domains with DNS records.
Domains — Get DetailSupportedOptionalReturns domain object + sending DNS records.
Domains — Add/Delete/VerifyNot SupportedOptionalUse wemail console for domain management.
Domains — Connection/Tracking/DKIMNot SupportedOptional
Suppressions — Bounces (List)SupportedOptionalList only. Add/delete individual bounces not supported.
Suppressions — Bounces (CRUD)Not SupportedOptional
Suppressions — Complaints (List)SupportedOptionalList only.
Suppressions — Complaints (CRUD)Not SupportedOptional
Suppressions — Unsubscribes (List)SupportedOptionalList only.
Suppressions — Unsubscribes (CRUD)Not SupportedOptional
Routes (Inbound Routing)Not SupportedOptional
Mailing Lists (CRUD + Members)Not SupportedOptional
Templates (CRUD + Versions)Not SupportedOptionaltemplate field supported in send but CRUD not available.
Stats (Domain/Aggregates)Not SupportedOptional
Tags (List/Get/Stats/Delete)Not SupportedOptionalTags can be set via o:tag but tag management not available.
IPs (List/Dedicated)Not SupportedOptional
Email ValidationNot SupportedOptionalUse wemail /v3/validate endpoint instead.
Webhooks (CRUD)Not SupportedOptionalUse wemail webhook configuration.
SubaccountsNot SupportedOptional
Keys (CRUD)Not SupportedOptionalUse wemail console.
Credentials (SMTP)Not SupportedOptional

Field-Level Compatibility

Detailed breakdown of every request field and response field across all supported endpoints.

POST /:domain/messages — Request Fields

ParameterTypeRequiredDescription
fromSupportedRequiredSender address. RFC 5322 format accepted (Name <email>).
toSupportedRequiredComma-separated recipients.
ccSupportedOptionalComma-separated CC recipients.
bccSupportedOptionalComma-separated BCC recipients.
subjectSupportedOptionalRequired unless template is set.
textSupportedOptionalPlain-text body.
htmlSupportedOptionalHTML body.
templateSupportedOptionalwemail template name.
o:tagSupportedOptionalTags (max 10). Multiple o:tag fields allowed.
o:trackingSupportedOptionalyes/no — enable/disable all tracking.
o:tracking-opensSupportedOptionalyes/no — open tracking.
o:tracking-clicksSupportedOptionalyes/no/htmlonly — click tracking.
o:deliverytimeSupportedOptionalRFC 2822 date for scheduled delivery.
o:testmodeSupportedOptionalyes — send in test mode.
o:sending-ip-poolSupportedOptionalPassed through to wemail pool field.
h:X-HeaderSupportedOptionalCustom headers via h: prefix.
v:variableSupportedOptionalCustom variables via v: prefix. Stored as metadata.
recipient-variablesSupportedOptionalJSON string of per-recipient variables.
t:variablesSupportedOptionalTemplate variables as JSON string.
attachmentNot SupportedOptionalFiles consumed by parser but not forwarded.
inlineNot SupportedOptionalInline images not supported.
o:dkimNot SupportedOptionalIgnored. DKIM handled by wemail.
o:require-tlsNot SupportedOptionalIgnored.
o:skip-verificationNot SupportedOptionalIgnored.
o:time-zone-localizeNot SupportedOptionalIgnored.

POST /:domain/messages — Response

ParameterTypeRequiredDescription
idSupportedOptional<message-id@domain> format.
messageSupportedOptional"Queued. Thank you." on success.

GET /:domain/events — Request & Response

ParameterTypeRequiredDescription
event (query)SupportedOptionalFilter: delivered, failed, opened, clicked, complained, accepted, rejected, unsubscribed.
recipient / to (query)SupportedOptionalFilter by recipient email.
begin (query)SupportedOptionalUnix timestamp start.
end (query)SupportedOptionalUnix timestamp end.
limit (query)SupportedOptionalMax 300.
from / subject / message-id / tags (query)Not SupportedOptionalAccepted but ignored.
ascending (query)Not SupportedOptionalAlways descending.
Response: items[].eventSupportedOptionalMapped event type name.
Response: items[].timestampSupportedOptionalUnix timestamp.
Response: items[].recipientSupportedOptionalRecipient email.
Response: items[].envelopeSupportedOptionalsender, targets, transport.
Response: items[].message.headersSupportedOptionalto, from, subject, message-id.
Response: items[].tagsSupportedOptionalMessage tags array.
Response: items[].user-variablesSupportedOptionalCustom variables from v: fields.
Response: items[].delivery-statusSupportedOptionalOn delivered/failed events: code, message, tls, mx-host.
Response: items[].geolocationSupportedOptionalOn open/click/unsubscribe: country, region, city.
Response: items[].client-infoSupportedOptionalOn open/click: client-name, client-os, device-type.
Response: pagingSupportedOptionalnext/previous URLs.

GET /domains & GET /domains/:domain

ParameterTypeRequiredDescription
Response: nameSupportedOptionalDomain name.
Response: stateSupportedOptionalactive or unverified.
Response: typeHardcodedOptionalAlways custom.
Response: created_atSupportedOptionalUTC date string.
Response: smtp_loginSupportedOptionalpostmaster@domain.
Response: sending_dns_recordsSupportedOptionalTXT/CNAME records with valid/invalid status.
Response: receiving_dns_recordsHardcodedOptionalAlways empty array.
Response: require_tlsHardcodedOptionalAlways false.
Response: wildcardHardcodedOptionalAlways false.

GET /:domain/bounces, complaints, unsubscribes

ParameterTypeRequiredDescription
limit (query)SupportedOptionalMax results per request.
Response: items[].addressSupportedOptionalSuppressed email address.
Response: items[].created_atSupportedOptionalUTC date string.
Response: items[].code (bounces)HardcodedOptionalAlways 550. Actual SMTP code not preserved.
Response: items[].error (bounces)SupportedOptionalBounce reason text.
Response: items[].tags (unsubscribes)HardcodedOptionalAlways ["*"].
Response: pagingSupportedOptionalprevious/first/next/last URLs.
ScopeAccount-wideOptionalDomain 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.

LanguagePackageInstallRegistry
Node.jsmailgun.jsnpm
PythonrequestsPyPI
PHPmailgun/mailgun-phpPackagist
Rubymailgun-rubyRubyGems
Gomailgun-goGitHub
Javamailgun-javaMaven
C#RestSharpNuGet

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
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>"
Node.js
// 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." }
Python
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
<?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>',
]);
Ruby
# 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>'
})
Go
// 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)
}
Java
// 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());
    }
}
C#
// 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);
Response
{
  "id": "<msg-id@yourdomain.com>",
  "message": "Queued. Thank you."
}