MailKite
Get your API key
All guides Sending email

Send email with Postmark

Transactional email is the mail your app sends one recipient at a time — receipts, password resets, magic links, notifications. This guide sends one through Postmark, over both the API and SMTP, then shows the same send on MailKite.

What you'll need

  • A domain you control, with access to its DNS records.
  • A Server API token from a Postmark server in your account.

Part 1 — Send with Postmark

1. Authenticate your domain

So your mail passes authentication and lands in the inbox, add your domain under Sender Signatures → Domains and publish the records Postmark shows you — a DKIM TXT record and a custom Return-Path CNAME:

DNS — yourdomain.com
Type    Name                              Value
TXT 20240101._domainkey.yourdomain.com k=rsa; p=… (DKIM shown in your dashboard)
CNAME pm-bounces.yourdomain.com pm.mtasv.net (custom Return-Path)

Postmark shows the exact per-domain DKIM selector and value in the dashboard — copy them from there, then click Verify.

2. Send over the API

POST to Postmark's email endpoint with your Server API token in the X-Postmark-Server-Token header. The From address must be on the domain you just authenticated:

send
curl -X POST https://api.postmarkapp.com/email \
-H "X-Postmark-Server-Token: $POSTMARK_SERVER_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"From": "hello@yourdomain.com",
"To": "ada@example.com",
"Subject": "Your invoice #1042",
"HtmlBody": "<p>Thanks! Your receipt is attached.</p>",
"TextBody": "Thanks! Your receipt is attached.",
"MessageStream": "outbound"
}'
response
200 OK
{
"To": "ada@example.com",
"SubmittedAt": "2024-01-01T12:00:00.0000000-05:00",
"MessageID": "b7bc2f4a-e38e-4336-af7d-e6c392c2f817",
"ErrorCode": 0,
"Message": "OK"
}

A 200 with "ErrorCode": 0 means Postmark accepted the message.

3. Or send over SMTP

Prefer SMTP? Point your app at Postmark's relay. Your Server API token is both the username and the password, and the X-PM-Message-Stream header selects the message stream:

smtp
Host:      smtp.postmarkapp.com
Port: 587 # STARTTLS (25 or 2525 also work)
Username: $POSTMARK_SERVER_TOKEN # your Server API token
Password: $POSTMARK_SERVER_TOKEN # the same token
Header: X-PM-Message-Stream: outbound

That's a transactional send on Postmark: authenticate the domain, then call the API or the SMTP relay.

Part 2 — The same, on MailKite

When we built sending into MailKite, we wanted three things to be true: one set of DNS records, one API key that works for both HTTP and SMTP, and a body you don't have to nest. Here's the same message.

1. Authenticate your domain

Publish three TXT records — SPF, a MailKite DKIM key, and DMARC. The same domain also receives mail once its MX points at MailKite:

DNS — yourdomain.com
Type   Name                              Value
TXT yourdomain.com v=spf1 include:mailkite.dev ~all
TXT mailkite._domainkey.yourdomain.com v=DKIM1; k=rsa; p=…
TXT _dmarc.yourdomain.com v=DMARC1; p=none;

The exact DKIM value is shown in the dashboard; MailKite verifies the records for you over DNS.

2. Send over the API

One POST /v1/send with a flat from/to/ subject/html body. A 202 means it's queued:

Pick your language in the card — the dashboard and the AI assistant do the same send, and every SDK takes the same fields:

send
import { MailKite } from "mailkite";

const mk = new MailKite(process.env.MAILKITE_API_KEY);

const { id, status } = await mk.send({
from: "hello@myapp.ai",
to: "ada@example.com",
subject: "Your invoice #1042",
html: "<p>Thanks! Receipt attached.</p>",
});
Install Docs →
response
202 Accepted
{ "id": "msg_2Hk9…", "status": "queued" }

3. Or send over SMTP

The same key is your SMTP password — no separate credential to generate:

smtp
import nodemailer from "nodemailer";

const tx = nodemailer.createTransport({
host: "smtp.mailkite.dev",
port: 587, // STARTTLS · use 465 for implicit TLS
auth: {
user: "mailkite", // any username works
pass: process.env.MAILKITE_API_KEY, // your mk_live_… key
},
});

await tx.sendMail({
from: "hello@myapp.ai", // an address on a verified domain
to: "ada@example.com",
subject: "Your invoice #1042",
html: "<p>Thanks! Receipt attached.</p>",
});

See Send API and SMTP relay for the full reference — attachments, headers, and delivery events.

A little about MailKite

MailKite is programmable email for developers and AI agents. One API key and one set of DNS records cover both directions: send with a single POST (or the SMTP relay), and the same verified domain receives replies as a signed webhook of clean JSON. Behind the send, MailKite routes across multiple providers to keep you in the inbox — and any address can be handed to an agent that reads and replies on its own. Sending and receiving are on the free tier.

Next: the Send API for attachments and delivery tracking, or the Quickstart to get a verified domain and API key.