Send your first transactional email
From a sender domain to your first transactional email: add and verify the domain, create an API key, send with curl, Node or SMTP.
postfly is invite-only, so you need an account and a project first. Everything below can be done in the dashboard; the API calls are shown for when you want to automate it.
1 · Add a sender domain
Mail goes out from your own domain, so start by adding it: Domains → Add domain in the dashboard, or POST /v1/domains with a key that has domains:write. The domain starts as pending. A project can have up to 50 sender domains, and a domain belongs to one project only.
2 · Publish the DNS records
The domain page lists the records to publish at your DNS provider, with the exact values for your domain (the DKIM key is generated for it). They look like this:
| Type | Name | Value | Purpose |
|---|---|---|---|
| TXT | yourdomain.com | v=spf1 include:_spf.postfly.app ~all | SPF |
| TXT | postfly._domainkey.yourdomain.com | v=DKIM1;h=sha256;k=rsa;p=MIIBIjANBg… | DKIM |
| TXT | _dmarc.yourdomain.com | v=DMARC1; p=none; rua=mailto:[email protected]; … | DMARC |
| MX | yourdomain.com | 10 mail.postfly.app | Optional |
If the domain already has an SPF record, don't add a second one: postfly shows your current record with its include: merged in, to publish in place of the old one. The MX record is optional and not checked; leave it out on a domain whose mail you receive elsewhere. Sender domains & DNS explains each record.
3 · Verify
Click Re-check now on the domain page, or call POST /v1/domains/{domain}/verify. When SPF, DKIM and DMARC all pass, the domain becomes verified and can send. DNS changes can take a while to show up; postfly also re-checks pending domains once a day for their first 30 days and emails you when one passes. To look yourself:
dig +short TXT postfly._domainkey.yourdomain.com
dig +short TXT _dmarc.yourdomain.com4 · Create an API key
In API tokens → Create token, pick Sending only (the emails:send scope) for an app that only sends, and optionally restrict the key to the domain you just verified. The key (pf_live_… or pf_test_…) is shown once; keep it in your secret store and pass it as POSTFLY_API_KEY.
5 · Send an email
One request per recipient. from must be an address on a verified domain of the project; html, text or both make the body.
curl -X POST https://api.postfly.app/v1/emails \
-H "Authorization: Bearer $POSTFLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "[email protected]",
"to": "[email protected]",
"subject": "Welcome aboard",
"html": "<p>Thanks for signing up.</p>",
"tag": "welcome"
}'The API answers right away; delivery happens in the background:
{
"id": "m_3kTq9ZbW2xYv",
"status": "queued",
"createdAt": "2026-09-11T10:00:00.000Z"
}SMTP takes the same key as the password (user apikey) on smtp.postfly.app:587 with STARTTLS — see SMTP.
6 · Track delivery
GET /v1/emails/{id} returns the message and its status: queued → sending → sent (accepted by our mail server) → delivered (accepted by the recipient's server), or bounced, complained, failed. The dashboard's Activity shows the same timeline, and a webhook pushes each change to your endpoint.