Postmark MCP Server
About
An MCP server for sending emails via the Postmark service, configured through environment variables.
Details
- Author
- ActiveCampaign
- Downloads
- 279
- Categories
- Communication, Automation, API, Other
Jump to
- Exposes an MCP server for sending emails via Postmark
- Simple configuration via environment variables
- Comprehensive error handling and graceful shutdown
- Secure logging practices (no sensitive data exposure)
- Automatic email tracking configuration
Setting up with Highlight
This MCP is not yet compatible with Highlight’s one-click setup. However, you can still use it with Highlight by following these steps:
- Download and install Highlight from highlightai.com/download
- Navigate to the plugins tab and select "Add Custom Plugin"
-
Configure the plugin with the settings below
Plugin Name
Postmark MCP ServerCommand (node, npx, python, etc.)Please refer to the README for specific instructions on how to obtain API keys or other required environment variables.
- Enable "Start Automatically" if you want the plugin to start when Highlight launches
From the repository
Configure the server via environment variables. Requires Node.js v16 or higher and a Postmark account with a server token.
Claude Desktop / Cursor
Paste into your MCP client config file to install this server.
{
"mcpServers": {
"postmark mcp server": {
"postmark": {
"command": "node",
"args": [
"path/to/postmark-mcp/index.js"
],
"env": {
"POSTMARK_SERVER_TOKEN": "your-postmark-server-token",
"DEFAULT_SENDER_EMAIL": "your-sender-email@example.com",
"DEFAULT_MESSAGE_STREAM": "your-message-stream"
}
}
}
}
}
McpServers
{
"postmark": {
"command": "node",
"args": [
"path/to/postmark-mcp/index.js"
],
"env": {
"POSTMARK_SERVER_TOKEN": "your-postmark-server-token",
"DEFAULT_SENDER_EMAIL": "your-sender-email@example.com",
"DEFAULT_MESSAGE_STREAM": "your-message-stream"
}
}
}
Send emails with Postmark using Claude and other MCP-compatible AI assistants.
- π API Documentation
- π API Explorer
- π Engineering Articles
- π Changelogβ what's new in each release
We'd love to hear from you! Please share your feedback and suggestions using ourfeedback form.
- Node.js v20 or higher
- APostmark accountand server token
git clone https://github.com/ActiveCampaign/postmark-mcp cd postmark-mcp
Create your own environment file from the example
Edit your.envto contain your Postmark credentials and settings.
Important:This is intended for local development purposes only. Secrets should never be stored in version control and.envtype files should be added to.gitignore.
npm start # or yarn start # or bun start
The repo ships two smoke-test example files. Copy each to its non-example name (which is gitignored) before running, so your local edits β including any verified-sender addresses β never end up committed.
# Read-only suite (25 checks). Optionally edit RECIPIENT_WITH_HISTORY. cp smoke-test.example.mjs smoke-test.mjs npm run smoke # Mutating suite (full lifecycles + real email sends). # REQUIRED: edit SENDER and RECIPIENT to two of your verified addresses. cp smoke-test-mutating.example.mjs smoke-test-mutating.mjs node smoke-test-mutating.mjs
The read-only suite spawns the server over stdio and exercises every read tool against your Postmark account, plus the validation paths foreditTemplateandcreateWebhook. Does not send mail or mutate state.
The mutating suite runs full createβeditβdelete lifecycles for templates (including layout binding), webhooks, and suppressions, and sends real emails between the two addresses you configure. It cleans up after itself. The script refuses to run while the placeholder values are still in place.
After installing the MCP, update your configuration to set:
- POSTMARK_SERVER_TOKEN
- DEFAULT_SENDER_EMAIL
- DEFAULT_MESSAGE_STREAM(default:outbound)
Using npx (recommended β no clone required)
Install directly from npm without managing a local copy:
{ "mcpServers": { "postmark": { "command": "npx", "args": ["-y", "@activecampaign/postmark-mcp"], "env": { "POSTMARK_SERVER_TOKEN": "your-postmark-server-token", "DEFAULT_SENDER_EMAIL": "your-sender-email@example.com", "DEFAULT_MESSAGE_STREAM": "outbound" } } } }
{ "mcpServers": { "postmark": { "command": "node", "args": ["/absolute/path/to/postmark-mcp/index.js"], "env": { "POSTMARK_SERVER_TOKEN": "your-postmark-server-token", "DEFAULT_SENDER_EMAIL": "your-sender-email@example.com", "DEFAULT_MESSAGE_STREAM": "outbound" } } } }
Both snippets work withClaude Desktop(~/Library/Application Support/Claude/claude_desktop_config.json),Cursor(.cursor/mcp.json), and any other MCP client that accepts the standard JSON configuration format.
This section provides a complete reference for the Postmark MCP server tools including example prompts and payloads. The server registers24 toolsorganized into eight categories.
- sendEmail
- sendEmailWithTemplate
- sendBatch
- sendBatchWithTemplate
- listTemplates
- getTemplate
- createTemplate
- editTemplate
- deleteTemplate
- validateTemplate
- searchOutboundMessages
- getMessageDetails
- searchBounces
- getBounceDump
- activateBounce
- listSuppressions
- createSuppressions
- deleteSuppressions
- listWebhooks
- createWebhook
- deleteWebhook
Sends a transactional email to one recipient or up to 50 recipients.
Send an email using Postmark to recipient@example.com with the subject "Meeting Reminder" and the message "Don't forget our team meeting tomorrow at 2 PM."
{ "to": "recipient@example.com", "subject": "Meeting Reminder", "textBody": "Don't forget our team meeting tomorrow at 2 PM.", "htmlBody": "<p>Don't forget our team meeting tomorrow at 2 PM.</p>", "from": "sender@example.com", "cc": "manager@example.com", "bcc": "archive@example.com", "replyTo": "support@example.com", "tag": "meetings" }
toaccepts a single address or an array of up to 50 addresses.htmlBody,from,cc,bcc,replyTo, andtagare optional. Iffromis omitted,DEFAULT_SENDER_EMAILis used.
Email sent successfully! MessageID: 0a1b2c3d-... To: recipient@example.com Subject: Meeting Reminder
Sends an email using a Postmark template.
Send the "welcome" template to customer@example.com with name "John Doe" and login_url "https://myapp.com/login".
{ "to": "customer@example.com", "templateAlias": "welcome", "templateModel": { "name": "John Doe", "login_url": "https://myapp.com/login" }, "from": "sender@example.com", "tag": "onboarding" }
ProvideeithertemplateId(number)ortemplateAlias(string), not both.
Template email sent successfully! MessageID: 0a1b2c3d-... To: customer@example.com Template: welcome
Sends up to 500 emails in a single API call. Each message is fully independent β its own recipient, subject, and body. This wraps Postmark'ssynchronousbatch endpoint (POST /email/batch), which returns immediate per-message results.
Note:Postmark also offers an asynchronousbulk email API(POST /email/bulk) for large-volume jobs with no message-count cap and a 50 MB payload limit. That endpoint uses a submit-and-poll workflow and is not currently wrapped by this MCP server.
{ "messages": [ { "to": "alice@example.com", "subject": "Order #1234 confirmed", "textBody": "Thanks Alice β your order is on its way.", "tag": "order-confirmation" }, { "to": "bob@example.com", "subject": "Order #1235 confirmed", "textBody": "Thanks Bob β your order is on its way.", "tag": "order-confirmation" } ] }
Per-message fields:to,subject,textBodyare required.htmlBody,from,cc,bcc,replyTo, andtagare optional. Iffromis omitted on a message,DEFAULT_SENDER_EMAILis used.
Sent 2/2 successfully Successes: - alice@example.com β abc-123-def - bob@example.com β abc-456-ghi
When some messages fail at submission (e.g., suppressed recipients), failures are listed first with theirErrorCodeand reason:
Sent 8/10 successfully (2 failed) Failures: - blocked@example.com β 406: Address has been suppressed. - bad@example.com β 300: Inactive recipient ...
Sends up to 500 templated emails β same template, per-recipient template models. Ideal for "render this onboarding template for each new user" flows.
{ "templateAlias": "welcome", "from": "hello@yourapp.com", "tag": "onboarding", "recipients": [ { "to": "alice@example.com", "templateModel": { "name": "Alice", "plan": "Pro" } }, { "to": "bob@example.com", "templateModel": { "name": "Bob", "plan": "Free" } } ] }
ProvideeithertemplateId(number)ortemplateAlias(string). Top-levelfromandtagapply to all recipients but can be overridden per-recipient. Each recipient also accepts optionalcc,bcc, andreplyTo.
Lists saved templates on this server. Returns the first 100 templates; if a server has more than 100, pagination is not yet supported and the response will indicate that results are truncated.
Found 2 templates: β’ Welcome - ID: 12345678 - Alias: welcome - Subject: Welcome to {{product_name}}
Retrieves a single template's full content (HTML body, text body, subject, type).
Payload:{ "templateIdOrAlias": "welcome" }β accepts numeric ID or string alias.
Creates a new template. Requiresname. At least one ofhtmlBodyortextBodymust be provided.
subjectis required for Standard templates and must beomittedfor Layout templates β Postmark rejects the field on Layouts.
layoutTemplate(Standard only) binds the new template to an existing Layout by alias. Without it, the new template renders unwrapped (no chrome from any layout).
{ "name": "Order Confirmation", "subject": "Your order #{{order_id}} is confirmed", "htmlBody": "<h1>Thanks {{name}}</h1>", "textBody": "Thanks {{name}}", "alias": "order-confirmation", "templateType": "Standard", "layoutTemplate": "basic" }
templateTypemay be"Standard"(default) or"Layout".
Updates an existing template. RequirestemplateIdOrAliasplusat least oneupdated field (name,subject,htmlBody,textBody,alias, orlayoutTemplate).
Pass"layoutTemplate": nullto unbind a template from its current Layout (the MCP translates this to the empty-string the Postmark API requires for clearing the association).
Permanently deletes a template by ID or alias. Layout templates cannot be deleted while Standard templates are still bound to them β unbind viaeditTemplatefirst.
Payload:{ "templateIdOrAlias": "order-confirmation" }
Validates template content (Mustachio syntax, undefined variables) without saving. At least one ofsubject,htmlBody, ortextBodyis required.
{ "subject": "Order #{{order_id}}", "htmlBody": "<p>Thanks {{name}}</p>", "textBody": "Thanks {{name}}", "testRenderModel": { "order_id": 42, "name": "John" }, "templateType": "Standard" }
Expected Payload (all filters optional):
{ "recipient": "user@example.com", "fromEmail": "sender@example.com", "tag": "marketing", "subject": "Welcome", "status": "sent", "messageStream": "outbound", "fromDate": "2025-05-01", "toDate": "2025-05-15", "count": 50, "offset": 0 }
statusis one ofqueued,sent,processed.countis 1β500 (default 50).
Retrieves full details and event timeline for a single outbound message.
Payload:{ "messageId": "0a1b2c3d-..." }
Composite triage tool. Answers "did my email reach X, and if not, why?" by running message search, suppression check, and bounce history lookups in parallel against a recipient address, then synthesizing a plain-English recommendation.
This is adiagnostictool: it composes multiple Postmark API calls into a single coherent answer rather than mirroring a single endpoint.
Did my email to recipient@example.com get delivered? If not, what should I do?
{ "recipient": "recipient@example.com", "messageId": "0a1b2c3d-...", "fromDate": "2026-04-21", "toDate": "2026-04-28", "messageStream": "outbound" }
All fields exceptrecipientare optional. IfmessageIdis omitted, the most recent message to the recipient is used. The default search window is the last 7 days.
Delivery Diagnosis: recipient@example.com ββββββββββββββββββββββββββββββββββββββββββββββββ Suppression: not suppressed on stream "outbound" Most recent message: MessageID: fadeae4e-fb04-4102-9303-9876078c7b81 Subject: Welcome to MyApp Sent: 2026-04-27T18:42:19.0000000-04:00 Status: Sent Events: Delivered, OpenedΓ2, Clicked Bounce history: none Recommended action: Email was delivered. If recipient says they didn't see it, check their spam folder or ask them to whitelist the sender domain.
When the recipient is suppressed, the recommendation differs based on reason:SpamComplaintis permanent,HardBouncemay be reactivatable,ManualSuppressioncan be deleted viadeleteSuppressions.
Searches the bounce log with optional filters by type, recipient, tag, message ID, message stream, date range, and active/inactive status.
{ "type": "HardBounce", "inactive": true, "emailFilter": "@example.com", "tag": "marketing", "messageID": "0a1b2c3d-...", "messageStream": "outbound", "fromDate": "2025-05-01", "toDate": "2025-05-15", "count": 50, "offset": 0 }
Returns the raw SMTP dump for a bounce. Bounce dumps are retained for 30 days.
Payload:{ "bounceId": 123456 }
Sign in to leave a review
Use Google, GitHub, or an email account so ratings stay tied to real people.
No reviews posted yet.


