Migrate from Postmark
A practical guide to moving your transactional email infrastructure from Postmark to Veil Mail, covering SDK changes, API mapping, and webhook migration.
Overview
Postmark is known for its focus on transactional email delivery. Veil Mail expands on this foundation with built-in PII scanning, CASL compliance, marketing campaigns, audience management, and a broader SDK ecosystem. If you're migrating from Postmark, the process is straightforward since both platforms share similar REST API patterns.
Key differences to note:
- Postmark uses Server Tokens for authentication; Veil Mail uses scoped API keys (
veil_live_/veil_test_) - Postmark has a separate endpoint for template emails; Veil Mail uses the same
/v1/emailsendpoint with atemplateIdfield - Postmark separates transactional and marketing into different "streams"; Veil Mail uses a
typefield on the email object - Veil Mail adds PII scanning, consent management, and automation that are not available in Postmark
Server Token to API Key Migration
Postmark uses Server Tokens (for sending) and Account Tokens (for management). Veil Mail consolidates these into a single API key that is scoped by environment and permissions.
Postmark
// Postmark Server Token
X-Postmark-Server-Token: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
// Postmark Account Token (for account-level API)
X-Postmark-Account-Token: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxVeil Mail
// Single API key scoped to environment
VEILMAIL_API_KEY=veil_live_xxxxx # Production
# VEILMAIL_API_KEY=veil_test_xxxxx # Testing (no emails sent)Note: Veil Mail API keys can be configured with granular permissions (send-only, read-only, full access) from the dashboard. You don't need separate tokens for different operations.
SDK Migration
Replace the postmark package with @resonia/veilmail-sdk.
# Remove Postmark
npm uninstall postmark
# Install Veil Mail
npm install @resonia/veilmail-sdkSend Email Comparison
Postmark
import { ServerClient } from 'postmark';
const client = new ServerClient(process.env.POSTMARK_SERVER_TOKEN!);
await client.sendEmail({
From: 'hello@yourdomain.com',
To: 'user@example.com',
Subject: 'Welcome!',
HtmlBody: '<h1>Welcome to our platform!</h1>',
TextBody: 'Welcome to our platform!',
MessageStream: 'outbound',
});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>',
text: 'Welcome to our platform!',
});Key difference: Postmark uses PascalCase field names (From, To, HtmlBody). Veil Mail uses camelCase (from, to, html), which is more idiomatic in JavaScript/TypeScript.
Template Email Comparison
Postmark
// Postmark uses a separate method for template emails
await client.sendEmailWithTemplate({
From: 'hello@yourdomain.com',
To: 'user@example.com',
TemplateAlias: 'welcome',
TemplateModel: {
firstName: 'Alice',
orderNumber: '12345',
},
MessageStream: 'outbound',
});Veil Mail
// Veil Mail uses the same send method with a templateId field
await client.emails.send({
from: 'hello@yourdomain.com',
to: 'user@example.com',
templateId: 'template_xxxxx',
templateData: {
firstName: 'Alice',
orderNumber: '12345',
},
});Batch Email Comparison
Postmark
await client.sendEmailBatch([
{
From: 'hello@yourdomain.com',
To: 'user1@example.com',
Subject: 'Hello User 1',
HtmlBody: '<p>Welcome!</p>',
MessageStream: 'outbound',
},
{
From: 'hello@yourdomain.com',
To: 'user2@example.com',
Subject: 'Hello User 2',
HtmlBody: '<p>Welcome!</p>',
MessageStream: 'outbound',
},
]);Veil Mail
await client.emails.sendBatch([
{
from: 'hello@yourdomain.com',
to: 'user1@example.com',
subject: 'Hello User 1',
html: '<p>Welcome!</p>',
},
{
from: 'hello@yourdomain.com',
to: 'user2@example.com',
subject: 'Hello User 2',
html: '<p>Welcome!</p>',
},
]);API Endpoint Mapping
Postmark endpoints are hosted at https://api.postmarkapp.com. Veil Mail endpoints are at https://api.veilmail.xyz.
| Postmark | Veil Mail | Notes |
|---|---|---|
| POST /email | POST /v1/emails | Similar payload, camelCase fields |
| POST /email/batch | POST /v1/emails/batch | Direct mapping |
| GET /templates | GET /v1/templates | Direct mapping |
| POST /email/withTemplate | POST /v1/emails | Use templateId field |
| POST /email/batchWithTemplates | POST /v1/emails/batch | Use templateId field per email |
| GET /deliverystats | GET /v1/analytics/overview | Richer analytics response |
| GET /bounces | GET /v1/suppressions | Unified suppression list |
| GET /message-streams | -- | Use type field instead |
Simplified templates: Postmark has separate endpoints for sending with and without templates (/email vs /email/withTemplate). Veil Mail unifies these into a single POST /v1/emails endpoint -- just include templateId when you want to use a template.
Webhook Migration
Postmark webhooks use PascalCase event types. Veil Mail uses namespaced, lowercase event types.
| Postmark Event | Veil Mail Event |
|---|---|
| Delivery | email.delivered |
| Bounce | email.bounced |
| SpamComplaint | email.complained |
| Open | email.opened |
| Click | email.clicked |
| SubscriptionChange | subscriber.unsubscribed |
Postmark includes a RecordType field in the payload. Veil Mail uses a top-level type field. Update your webhook handler accordingly:
// Before: Postmark webhook handler
app.post('/webhooks/postmark', (req, res) => {
const { RecordType } = req.body;
switch (RecordType) {
case 'Delivery':
handleDelivery(req.body);
break;
case 'Bounce':
handleBounce(req.body);
break;
case 'SpamComplaint':
handleComplaint(req.body);
break;
}
res.sendStatus(200);
});
// After: Veil Mail webhook handler
app.post('/webhooks/veilmail', (req, res) => {
// Verify signature
const signature = req.headers['x-veilmail-signature'] as string;
// ... verify with HMAC-SHA256
const { type, data } = req.body;
switch (type) {
case 'email.delivered':
handleDelivery(data);
break;
case 'email.bounced':
handleBounce(data);
break;
case 'email.complained':
handleComplaint(data);
break;
}
res.json({ received: true });
});Important: Postmark does not require webhook signature verification. Veil Mail includes an X-VeilMail-Signature header on every webhook delivery and we strongly recommend verifying it to prevent spoofed events.
What You Gain
Postmark is excellent for transactional email. Veil Mail gives you everything Postmark offers plus a comprehensive marketing and compliance toolkit.
- Automatic PII protection -- every email is scanned for sensitive data (SSNs, credit cards, health records) before delivery
- Built-in CASL compliance -- consent tracking, unsubscribe management, and physical address enforcement
- Marketing campaigns -- Postmark's broadcast streams are limited compared to Veil Mail's full campaign builder with A/B testing and scheduling
- Audience management -- first-class subscriber management with custom properties, segments, and signup forms
- Automation sequences -- build drip campaigns and multi-step email workflows with branching logic
- SDKs for every language -- official SDKs for Node.js, Python, Go, Ruby, PHP, Java, .NET, Rust, Elixir, and more
- Unified API -- no separate endpoints for template vs. non-template sends, and no message streams to manage