Migration illustration Migration guide

Migrate to Mailtrap from Postmark

A complete technical guide to switch from Postmark to Mailtrap. Most teams complete the migration in under an hour.

Migration Checklist

  1. Authenticate your domain
    Add and verify your domain before sending. Follow the Domain Setup article at docs.mailtrap.io.

Need some help?

Contact our support and our developers will help you with it.

Need some help?
  1. Get your API token
    Mailtrap auto-generates a token when you add a domain. Find it under Settings → API Tokens. Read more on API tokens.
  2. Update your integration
    Swap your Postmark endpoints and credentials for Mailtrap’s (API or SMTP). See the migration sections below.
  3. Migrate templates
    Note that Postmark uses Mustachio and Mailtrap uses Handlebars. See the templates sections below.
  4. Migrate suppressions
    Export Postmark suppressions and import them into Mailtrap via CSV or manually. Click here for more information.
  5. Migrate users
    Add users from the User Management tab and review permissions during migration.
  6. Set up webhooks
    Follow the Mailtrap Webhooks step-by-step guide.
  7. Security and compliance
    Visit the Trust Center page to review Mailtrap’s security practices and compliance standards.

Mailtrap tip

You can use ActionMailer Balancer Ruby gem to proportionally distribute the email sending load between two different sending services (e.g. 70% Postmark and 30% Mailtrap) to mitigate the sending risks.

 

Mailtrap tip

Concepts

Before going over the technical details, it’s important to clear up some key concepts.

Sending domains

Postmark equivalent: Domains + Sender Signatures

Postmark manages sender identity under Sender Signatures, which supports two options: 

  1. Individual email address verification (Sender Signature)
  2. Full domain verification (Domain)

For production sending, domain verification is recommended – it requires adding DKIM DNS records, and optionally a Return-Path CNAME record for SPF/DMARC alignment and bounce tracking.

Mailtrap’s domain setup uses the same DNS standards – SPF, DKIM, DMARC. DKIM records can be added alongside Postmark’s (different selectors, no conflict), and one DMARC record covers both. For SPF, however, you must merge Mailtrap’s include into your existing SPF record rather than adding a separate one.

See the Mailtrap domain setup guide for step-by-step instructions.

Separate sending streams

Postmark equivalent: Message Streams (Transactional + Broadcast)

This is one area where Postmark and Mailtrap are closely aligned. Postmark separates transactional and broadcast email via Message Streams, with distinct SMTP hosts:

  • Postmark: 
    • smtp.postmarkapp.com (transactional) 
    • smtp-broadcasts.postmarkapp.com (broadcast)
  • Mailtrap:
    • live.smtp.mailtrap.io (transactional)
    • bulk.smtp.mailtrap.io (bulk)

By keeping the sending infrastructures separate, you are able to:

  • Protect your transactional email reputation from the performance of your bulk campaigns
  • Ensure each stream routes through the right IP pools
  • Give mailbox providers the signals they need to categorize and deliver your emails correctly

Email categories

Postmark equivalent: Tags (single string per message, max 1,000 characters)

Both platforms use a single tag/category per message for grouping and analytics. Postmark uses the Tag field in the API and X-PM-Tag header in SMTP. Mailtrap Email Categories use the category field in the API and X-MT-Category header in SMTP.

Nearly identical approach; just rename the field/header.

Organization & sub-accounts

Postmark equivalent: Users and Permissions (Account Owner, Admin, Technical, Billing roles)

Postmark manages access through a Team system with four role types under Account settings. Mailtrap offers Organization and sub-account management from Business plan onwards. 

Terminology comparison

API migration

Authentication

Both platforms use a token in a request header, but with different header names:

PostmarkMailtrap
MethodServer API tokenBearer token
HeaderX-Postmark-Server-Token: YOUR_SERVER_TOKENAuthorization: Bearer YOUR_API_KEY
Account-levelSeparate X-Postmark-Account-Token headerSame token

Simple header rename; the auth model is conceptually the same.

API mapping

API typePostmarkMailtrapNotes
Transactional emailPOST https://api.postmarkapp.com/emailPOST https://send.api.mailtrap.io/api/sendSimilar flat JSON structures
Bulk emailPOST https://api.postmarkapp.com/email/batchPOST https://bulk.api.mailtrap.io/api/sendBoth support 500 messages/batch
Template sendingPOST https://api.postmarkapp.com/email/withTemplatePOST https://send.api.mailtrap.io/api/sendwith template_uuidPostmark has a dedicated template endpoint
Batch template sendingPOST https://api.postmarkapp.com/email/batchWithTemplatesPOST https://bulk.api.mailtrap.io/api/send with template_uuidPostmark wraps in {“Messages”: […]}
SuppressionsGET/POST /message-streams/{stream_id}/suppressions/dump and /suppressions, /suppressions/deleteGEThttps://mailtrap.io/api/accounts/{account_id}/suppressionsPostmark scopes suppressions per message stream
StatsGET /stats/outbound, /stats/outbound/sends, /bounces, /spam, /opens, /clicksGET/api/accounts/{account_id}/stats, /stats/domains, /stats/categories, /stats/email_service_providers, and  /stats/datePostmark has granular stats endpoints by type
Email logsGET /messages/outboundPOST /api/1.0/messages/{search,info,content}.jsonPostmark supports metadata-based search (metadata_* params)

Outbound Sending API JSON Field Mapping

FieldPostmarkMailtrap
From emailFrom (RFC 5322: “Name” <email>)from.email
From nameIncluded in From stringfrom.name
ToTo (comma-separated string)to[].email
CCCc (comma-separated string)cc[].email
BCCBcc (comma-separated string)bcc[].email
SubjectSubject (max 2,000 chars)subject
HTML bodyHtmlBody (max 5 MB)html
Text bodyTextBody (max 5 MB)text
Category/TagTag (single string, max 1,000 chars)category (single string)
Custom metadataMetadata (key-value object, searchable)custom_variables
Reply-ToReplyToreply_to object 
Custom headersHeaders[].{Name, Value}headers
Template identifierTemplateId (integer) or TemplateAlias (string)template_uuid
Template variablesTemplateModel (JSON object)template_variables (JSON object)
Inline CSSInlineCss (boolean, template sends only)Not supported – inline CSS before sending
Open trackingTrackOpens (boolean)Via account settings or headers
Click trackingTrackLinks (None, HtmlAndText, HtmlOnly, TextOnly)Via account settings or headers
AttachmentsAttachments[].{Name, Content, ContentType} (base64)attachments:[{content, filename, type, disposition}](base64)
Inline imagesAttachments[] with ContentID setattachments:[{content, filename, type, disposition:”inline”,content_id}]
Message streamMessageStream (e.g., “outbound”, “broadcast”)Determined by endpoint: send.api (transactional) vs bulk.api (bulk)

Code snippets

  • Mailtrap cURL SDK code snippet cURL
Postmark Postmark
curl -X POST https://api.postmarkapp.com/email \
  -H "X-Postmark-Server-Token: YOUR_SERVER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "From": "Sender Name <sender@yourdomain.com>",
    "To": "Recipient Name <recipient@example.com>",
    "Subject": "Welcome aboard",
    "HtmlBody": "<h1>Hello</h1><p>Welcome to the platform.</p>",
    "TextBody": "Hello. Welcome to the platform.",
    "Tag": "welcome",
    "TrackOpens": true,
    "TrackLinks": "HtmlAndText",
    "MessageStream": "outbound"
  }'
Mailtrap Mailtrap

Copy

curl -X POST https://send.api.mailtrap.io/api/send \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": {
      "email": "sender@yourdomain.com",
      "name": "Sender Name"
    },
    "to": [
      {
        "email": "recipient@example.com",
        "name": "Recipient Name"
      }
    ],
    "subject": "Welcome aboard",
    "html": "<h1>Hello</h1><p>Welcome to the platform.</p>",
    "text": "Hello. Welcome to the platform.",
    "category": "welcome"
  }'

Note: Postmark uses PascalCase field names (HtmlBody, TextBody) and comma-separated recipient strings. Mailtrap uses snake_case/lowercase fields and recipient arrays with separate email/name properties. Both use flat JSON – no deep nesting.

SMTP migration

SettingPostmark (Transactional)Postmark (Broadcast)Mailtrap (Transactional)Mailtrap (Bulk)
Hostsmtp.postmarkapp.comsmtp-broadcasts.postmarkapp.comlive.smtp.mailtrap.iobulk.smtp.mailtrap.io
Port587, 25, 2525587, 25, 2525587 (recommended), 25, 2525587 (recommended), 25, 2525
TLSAPI (HTTPS) – Required
SMTP – Required
Outbound to Recipients – Opportunistic TLS
API (HTTPS) – Required
SMTP – Required
Outbound to Recipients – Opportunistic TLS
Required (STARTTLS)Required (STARTTLS)
Auth methodCRAM-MD5, DIGEST-MD5, PLAIN, LOGINCRAM-MD5, DIGEST-MD5, PLAIN, LOGINPLAIN, LOGINPLAIN, LOGIN
UsernameServer API TokenServer API Tokenapi (literal string)api (literal string)
PasswordServer API Token (same as username)Server API TokenAPI tokenAPI token

Migration notes:

  • Host swap: Both platforms separate transactional and bulk/broadcast into distinct SMTP hosts. Replace smtp.postmarkapp.comlive.smtp.mailtrap.io and smtp-broadcasts.postmarkapp.combulk.smtp.mailtrap.io.
  • Username: Postmark uses the Server API Token as both username and password. Mailtrap uses the literal string api as username and the API token as password.
  • Ports: Same on both sides – 587, 25, 2525. No port changes needed.
  • SMTP headers: Replace X-PM-TagX-MT-Category, X-PM-Metadata-*X-MT-Custom-Variables, and X-PM-Message-Stream → use the appropriate Mailtrap SMTP host instead.

For more information on migrating your SMTP configuration, click this link. ⬅️

Rate limits & quotas

LimitPostmarkMailtrap
API rate limitNo published hard limit (returns 429 on excess) 150 requests per 10 seconds per API token
Batch size500 messages per batch call (50 MB payload max)500 emails per batch call
Message size10 MB (including attachments)10 MB default (extendable to 30 MB on request)
Max recipients per send50 (To + CC + BCC combined)Not publicly specified
Templates per server100 max200 max
Message streamsUp to 10 per serverTransactional + Bulk (fixed)

Email templates

Postmark uses Mustachio (a Mustache-inspired engine). Mailtrap uses Handlebars. The syntax is similar but not identical – you’ll need to review templates during migration.

Syntax comparison

PatternPostmark (Mustachio)Mailtrap (Handlebars)
Variable insertion{{variable_name}}{{variable_name}}
Nested access{{person.first_name}}{{person.first_name}}
Conditionals{{#var}}…{{/var}} (truthy check){{#if var}}…{{else}}…{{/if}}
Inverted/fallback{{^var}}default{{/var}}{{#if var}}{{var}}{{else}}default{{/if}}
Iteration{{#each items}}…{{/each}}{{#each items}}…{{/each}}
Raw HTML (unescaped){{{variable}}} or {{&variable}}{{{variable}}}
Date formattingNot supported – format before passingNot supported – format before passing
Pass variables via APITemplateModel (JSON object)template_variables (JSON object)
Template identifierTemplateId (integer) or TemplateAlias (string)template_uuid
Inline CSSInlineCss: true (template sends only)Not supported – inline before sending

Migration notes:

  • Variables and loops transfer directly – same {{var}} and {{#each}} syntax.
  • Conditionals need attention: Postmark uses {{#var}}...{{/var}} for truthy checks. Mailtrap Handlebars uses {{#if var}}...{{/if}}. Similarly, Postmark’s {{^var}}...{{/var}} becomes {{else}} blocks in Handlebars.
  • Variable passing is almost identical – both use a JSON object. Just rename the field from TemplateModel to template_variables.
  • Inline CSS: If you rely on Postmark’s InlineCss flag, you’ll need to inline CSS in your HTML before sending through Mailtrap, or use a build-step tool like juice to handle it.

Question icon

Frequently Asked Questions

  • Do I need to re-verify my domain if I’ve already set it up in Postmark?

    Yes, you’ll need to re-verify your domain. See the Mailtrap Knowledge Base for up-to-date guidance.

  • Why does Mailtrap have two separate SMTP hosts?

    Mailtrap separates transactional and bulk streams to protect your sender reputation and ensure proper delivery routing for each email type. Postmark does the same with Message Streams – you’re already familiar with this pattern.

  • Does Mailtrap offer migration assistance?

    Yes, Mailtrap offers migration assistance from Business plan onwards.

  • How do I migrate templates from Postmark?

    Both use Mustache-family syntax, so most template markup transfers with minor edits. Convert Postmark conditionals ({{#var}}...{{/var}}) to Handlebars ({{#if var}}...{{/if}}). Update API calls to use template_uuid instead of TemplateId/TemplateAlias, and pass variables via template_variables instead of TemplateModel.

  • What about Postmark’s Metadata search?

    Postmark lets you search messages by metadata key-value pairs (metadata_* query params). Mailtrap’s Email Logs provide filtering capabilities – check the current API docs for equivalent search options.

  • Can I migrate gradually?

    Yes. If you’re on Rails, Mailtrap’s ActionMailer Balancer lets you split traffic proportionally (e.g., 80% Postmark / 20% Mailtrap) and shift over time. For other frameworks, route by email type – move transactional first, then bulk.