Migrate from Mailgun
A comprehensive guide to moving your email infrastructure from Mailgun to Veil Mail, covering API changes, webhook migration, and feature differences.
Overview
Mailgun is a well-established email delivery service with both SMTP and REST API options. Veil Mail takes a modern, API-first approach with built-in privacy protections. The biggest architectural difference is that Mailgun scopes API calls by domain in the URL path, while Veil Mail uses a flat resource structure with the domain specified in the from field.
Key differences to be aware of:
- Mailgun uses domain-scoped endpoints (
/v3/{{domain}}/messages); Veil Mail uses flat endpoints (/v1/emails) - Mailgun supports SMTP relay; Veil Mail is API-only for better security and performance
- Mailgun uses Basic Auth with
api:key-xxx; Veil Mail uses Bearer token withveil_live_xxxxx - Veil Mail adds PII scanning, CASL compliance, and audience management features not available in Mailgun
SDK Migration
Replace the mailgun.js package with @resonia/veilmail-sdk.
# Remove Mailgun
npm uninstall mailgun.js form-data
# Install Veil Mail
npm install @resonia/veilmail-sdkSend Email Comparison
Mailgun
import Mailgun from 'mailgun.js';
import formData from 'form-data';
const mailgun = new Mailgun(formData);
const mg = mailgun.client({
username: 'api',
key: process.env.MAILGUN_API_KEY!,
});
await mg.messages.create('yourdomain.com', {
from: 'hello@yourdomain.com',
to: ['user@example.com'],
subject: 'Welcome!',
html: '<h1>Welcome to our platform!</h1>',
});Veil Mail
import { VeilMail } from '@resonia/veilmail-sdk';
const client = new VeilMail('veil_live_xxxxx');
await client.emails.send({
from: 'hello@yourdomain.com',
to: 'user@example.com',
subject: 'Welcome!',
html: '<h1>Welcome to our platform!</h1>',
});Key difference: Mailgun requires specifying the domain in the messages.create() call. Veil Mail infers the domain from the from address, making the API simpler. You also no longer need the form-data dependency.
Template Usage Comparison
Mailgun
await mg.messages.create('yourdomain.com', {
from: 'hello@yourdomain.com',
to: ['user@example.com'],
subject: 'Welcome!',
template: 'welcome-template',
'h:X-Mailgun-Variables': JSON.stringify({
firstName: 'Alice',
orderNumber: '12345',
}),
});Veil Mail
await client.emails.send({
from: 'hello@yourdomain.com',
to: 'user@example.com',
subject: 'Welcome!',
templateId: 'template_xxxxx',
templateData: {
firstName: 'Alice',
orderNumber: '12345',
},
});API Endpoint Mapping
Mailgun endpoints are domain-scoped. Veil Mail uses a flat resource structure. All Veil Mail endpoints are under https://api.veilmail.xyz.
| Mailgun | Veil Mail | Notes |
|---|---|---|
| POST /v3/{domain}/messages | POST /v1/emails | Domain specified in from field |
| GET /v3/{domain}/events | GET /v1/analytics/overview | Different response structure |
| GET /v3/domains | GET /v1/domains | Direct mapping |
| POST /v3/{domain}/templates | POST /v1/templates | Direct mapping |
| GET /v3/{domain}/bounces | GET /v1/suppressions | Unified suppression list |
| GET /v3/{domain}/stats | GET /v1/analytics/overview | Combined analytics endpoint |
Webhook Migration
Mailgun webhooks use different event names and payload structures. Veil Mail uses a consistent namespaced event format with simpler payloads.
| Mailgun Event | Veil Mail Event |
|---|---|
| delivered | email.delivered |
| failed (permanent) | email.bounced |
| failed (temporary) | email.deferred |
| opened | email.opened |
| clicked | email.clicked |
| complained | email.complained |
| unsubscribed | subscriber.unsubscribed |
Mailgun uses HMAC-SHA256 with a signing key for webhook verification. Veil Mail also uses HMAC-SHA256, but with a different header name:
// Mailgun verification (before)
const signature = req.body.signature;
// Verify using timestamp + token + signing key
// Veil Mail verification (after)
const signature = req.headers['x-veilmail-signature'] as string;
const isValid = crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(
crypto.createHmac('sha256', process.env.VEILMAIL_WEBHOOK_SECRET!)
.update(rawBody)
.digest('hex')
),
);What's Different
| Feature | Mailgun | Veil Mail |
|---|---|---|
| SMTP | Supported (SMTP relay) | API-only (more secure, faster) |
| Authentication | Basic Auth (api:key-xxx) | Bearer token with scoped keys |
| Endpoint Scoping | Domain-scoped URLs | Flat resource URLs |
| PII Scanning | Not available | Built-in, automatic |
| Email Validation | Separate paid add-on | Included with suppression checks |
| Log Retention | Plan-dependent | Full analytics with exportable reports |
SMTP users: If you're currently using Mailgun via SMTP relay, you'll need to switch to the REST API. Veil Mail does not support SMTP, but the REST API is simpler and provides better deliverability insights. The SDK handles all HTTP communication for you.
What You Gain
- Automatic PII protection -- every email is scanned for sensitive data before delivery, something Mailgun does not offer
- Built-in CASL compliance -- consent tracking, unsubscribe management, and physical address enforcement
- Simpler API surface -- no domain-scoped endpoints, no
form-datadependency, native TypeScript types - Campaigns and automation -- A/B testing, drip sequences, and automation workflows not available in Mailgun
- SDKs for every language -- official SDKs for Node.js, Python, Go, Ruby, PHP, Java, .NET, Rust, Elixir, and more
- RSS feeds and signup forms -- automated content delivery and embeddable subscriber forms built-in
- Environment-scoped keys -- test safely with
veil_test_keys instead of configuring separate test domains