Quick Start
Send your first transactional email in under five minutes. This guide walks through account creation, API key provisioning, sending domain verification, and your first live message — with real API calls you can run right now.
Prerequisites
- A PostMTA account. Sign up at postmta.com if you do not have one yet.
- curl or any HTTP client for making API calls.
- Access to add DNS records for the domain you want to send from (for SPF, DKIM, DMARC).
https://api.postmta.com. TLS 1.2+ is required on all connections.Step 1 — Create Account and Get API Key
Log into the dashboard at /app and navigate toSettings → API Keys. Click New API Key, give it a descriptive name (e.g., production-smtp-key), and copy the generated secret. Treat it like a password — it will not be shown again.
You can also create a key via the REST API:
curl -X POST https://api.postmta.com/v1/keys \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "production-smtp-key",
"permissions": ["messages:send", "domains:read", "webhooks:write"]
}'The response looks like this:
{
"id": "key_01HX5K9P7N3M4Q6R8T2V4W6Y8",
"name": "production-smtp-key",
"key": "pmk_live_abc123xyz789...",
"permissions": ["messages:send", "domains:read", "webhooks:write"],
"created_at": "2026-07-18T12:00:00Z",
"last_used_at": null
}key value now. It is only returned once and cannot be retrieved later.For SMTP AUTH, use the same key as the password. Your SMTP username is your PostMTA account ID (found on the dashboard Settings → General page).
Step 2 — Add and Verify a Sending Domain
A verified sending domain is required before you can inject mail into the PostMTA network. Domains are added via the dashboard or the API.
Add domain via API
curl -X POST https://api.postmta.com/v1/domains \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"domain": "mail.example.com",
"default": true
}'Response:
{
"id": "dom_01HX5K9P7N3M4Q6R8T2V4W6Y0",
"domain": "mail.example.com",
"status": "pending_verification",
"SPF_pass": false,
"DKIM_pass": false,
"DMARC_pass": false,
"created_at": "2026-07-18T12:01:00Z"
}Add DNS records
PostMTA provides three DNS records you must add to your domain's DNS zone. Go to your DNS provider and add the following records:
SPF Record
Create a TXT record on mail.example.com:
TXT mail.example.com "v=spf1 include:_spf.postmta.com ~all"DKIM Record
Create a CNAME record pointing to PostMTA's DKIM selector:
CNAME pmx1._domainkey.mail.example.com pmx1._domainkey.postmta.comDMARC Record
Create a TXT record on _dmarc.mail.example.com:
TXT _dmarc.mail.example.com "v=DMARC1; p=quarantine; rua=mailto:dmarc-reports@example.com"After adding all three records, click Verify DNS in the dashboard, or poll the domain endpoint until all three *_pass fields aretrue:
curl https://api.postmta.com/v1/domains/dom_01HX5K9P7N3M4Q6R8T2V4W6Y0 \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"Step 3 — Send Your First Email
With a verified domain and API key, you can now send your first message. Use the REST API or SMTP relay on port 2525 (lab) or 587 (production).
Send via REST API
curl -X POST https://api.postmta.com/v1/messages/send \
-H "Authorization: Bearer pmk_live_abc123xyz789..." \
-H "Content-Type: application/json" \
-d '{
"from": {
"address": "hello@mail.example.com",
"name": "Example Inc"
},
"to": [
{
"address": "alice@example.com",
"name": "Alice"
}
],
"subject": "Your order confirmation",
"html": "<h1>Order Confirmed</h1><p>Hi Alice, your order #12345 has shipped.</p>",
"headers": {
"X-Order-ID": "12345"
}
}'Successful response (HTTP 202):
{
"message_id": "msg_01HX5K9P7N3M4Q6R8T2V4W6Y8",
"status": "accepted",
"accepted_count": 1,
"rejected_count": 0,
"created_at": "2026-07-18T12:05:00Z"
}Send via SMTP
# Connect to the SMTP relay (lab endpoint)
nc -C mail.postmta.com 2525
# Authenticate
AUTH PLAIN AG1vbUBhY2NvdW50SUQgAHBta19saXZlX2FiYzEyM3h5ejc4OS4uLg==
# Send envelope
MAIL FROM: <hello@mail.example.com>
RCPT TO: <alice@example.com>
# Begin message body
DATA
From: Example Inc <hello@mail.example.com>
To: Alice <alice@example.com>
Subject: Your order confirmation
Content-Type: text/html; charset="UTF-8"
<html>
<body>
<h1>Order Confirmed</h1>
<p>Hi Alice, your order #12345 has shipped.</p>
</body>
</html>
.2525 for lab/testing environments. Use port 587 with STARTTLS for production submission.Step 4 — Track Delivery Status
Every message is assigned a unique message_id on acceptance. Poll the message endpoint or wait for a webhook to learn the final delivery outcome.
Poll delivery status via REST
curl https://api.postmta.com/v1/messages/msg_01HX5K9P7N3M4Q6R8T2V4W6Y8 \
-H "Authorization: Bearer pmk_live_abc123xyz789..."Example response:
{
"message_id": "msg_01HX5K9P7N3M4Q6R8T2V4W6Y8",
"from": {
"address": "hello@mail.example.com"
},
"to": ["alice@example.com"],
"subject": "Your order confirmation",
"status": "delivered",
"bounce_class": null,
"created_at": "2026-07-18T12:05:00Z",
"delivered_at": "2026-07-18T12:05:12Z",
"events": [
{
"type": "accepted",
"timestamp": "2026-07-18T12:05:00Z"
},
{
"type": "delivered",
"timestamp": "2026-07-18T12:05:12Z"
}
]
}Message status values
| Status | Meaning |
|---|---|
accepted | Message accepted for delivery; in the queue. |
delivered | Successfully delivered to the recipient's mail server. |
bounced | Delivery failed permanently. |
soft_bounced | Temporary failure; being retried. |
suppressed | Recipient is on a suppression list. |
Step 5 — Set Up Webhooks
Webhooks push real-time delivery events to your endpoint instead of requiring you to poll. Create a webhook to receive events for bounces, deliveries, and opens.
curl -X POST https://api.postmta.com/v1/webhooks \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.example.com/webhooks/postmta",
"events": [
"message.delivered",
"message.bounced",
"message.soft_bounced",
"message.suppressed"
],
"secret": "your-webhook-secret"
}'Response:
{
"id": "wh_01HX5K9P7N3M4Q6R8T2V4W6Y0",
"url": "https://your-app.example.com/webhooks/postmta",
"events": [
"message.delivered",
"message.bounced",
"message.soft_bounced",
"message.suppressed"
],
"status": "active",
"created_at": "2026-07-18T12:10:00Z"
}Webhook payload example
{
"event": "message.delivered",
"timestamp": "2026-07-18T12:05:12Z",
"data": {
"message_id": "msg_01HX5K9P7N3M4Q6R8T2V4W6Y8",
"from": "hello@mail.example.com",
"to": "alice@example.com",
"delivered_at": "2026-07-18T12:05:12Z"
}
}Verify webhook signatures using the PostMTA-Signature header. The signature is HMAC-SHA256 of the raw request body using your webhook secret.
const crypto = require('crypto');
const expected = crypto
.createHmac('sha256', webhookSecret)
.update(rawBody)
.digest('hex');
const signature = `sha256=${expected}`;
if (signature !== req.headers['postmta-signature']) {
return res.status(401).send('Invalid signature');
}Next Steps
- Authentication — deep dive into API keys and SMTP AUTH
- Sending Domains — domain verification and DNS records
- Sending Email — batch sends, personalization, attachments
- Webhooks — all supported events and retry behavior
- Bounces — hard vs. soft bounce classification
- Custom Headers — List-Unsubscribe, X-Priority, header injection protection