Matrix: M03M04
Open in panel — /app
Getting Started

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.

Estimated time: 5 minutes  | Prerequisites: a PostMTA account and at least one verified sending domain.

Prerequisites

All API calls in this guide use the base URL 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
}
Save the 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.com

DMARC 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"
DNS propagation can take up to 48 hours, though it is usually complete within a few minutes for most major DNS providers.

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>
.
SMTP ports: Use port 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

StatusMeaning
acceptedMessage accepted for delivery; in the queue.
deliveredSuccessfully delivered to the recipient's mail server.
bouncedDelivery failed permanently.
soft_bouncedTemporary failure; being retried.
suppressedRecipient 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