Domains
Register a sending domain, publish four DNS records, and understand what gates activation.
A mailbox lives on a domain you own. You register the domain once, publish the records Postbox gives you, and Postbox verifies them.
Register
import { Postbox } from "@postbox/sdk";
const pb = new Postbox({
apiKey: process.env.PB_KEY!,
projectId: process.env.PROJECT_ID!,
});
const domain = await pb.domains.create({
domain: "mail.acme.com",
region: "eu-west-1",
receivingEnabled: true,
});import os
from postbox import Postbox
pb = Postbox(api_key=os.environ["PB_KEY"], project_id=os.environ["PROJECT_ID"])
domain = pb.domains.create(
{
"domain": "mail.acme.com",
"region": "eu-west-1",
"receivingEnabled": True,
}
)using Postbox;
var pb = new PostboxClient(
new PostboxOptions
{
ApiKey = Environment.GetEnvironmentVariable("PB_KEY")!,
ProjectId = Environment.GetEnvironmentVariable("PROJECT_ID")!,
}
);
var domain = await pb.Domains.CreateAsync(
new DomainsCreateBody
{
Domain = "mail.acme.com",
Region = "eu-west-1",
ReceivingEnabled = true,
}
);import cloud.postboxapp.*;
import cloud.postboxapp.gen.*;
import java.util.*;
Postbox pb = new Postbox(PostboxOptions.builder()
.apiKey(System.getenv("PB_KEY"))
.projectId(System.getenv("PROJECT_ID"))
.build());
var domain = pb.domains.create(DomainsCreateBody.builder()
.domain("mail.acme.com")
.region("eu-west-1")
.receivingEnabled(true)
.build());import postbox "github.com/postboxapp/postbox-go"
pb, err := postbox.New(postbox.Options{
APIKey: os.Getenv("PB_KEY"),
ProjectID: os.Getenv("PROJECT_ID"),
})
ctx := context.Background()
domain, err := pb.Domains.Create(ctx, &postbox.DomainsCreateBody{
Domain: "mail.acme.com",
Region: "eu-west-1",
ReceivingEnabled: true,
})curl -X POST https://api.postboxapp.cloud/v1/domains \
-H "Authorization: Bearer $PB_KEY" \
-H "X-Project-Id: $PROJECT_ID" \
-H "Content-Type: application/json" \
-d '{
"domain": "mail.acme.com",
"region": "eu-west-1",
"receivingEnabled": true
}'| Field | Required | Notes |
|---|---|---|
domain | yes | Lowercased automatically. |
region | no | The sending region. Pinned at registration and not changeable afterward. |
receivingEnabled | no | Adds an MX record so the domain accepts inbound mail. |
A region is a sending region
region selects where mail is sent from, which matters for deliverability and
latency. It does not shard your data. Mailboxes, messages, and bodies live
in the EU database regardless of the sending region you pick.
GET /v1/domains/regions returns the allowed regions and the default.
The records you publish
GET /v1/domains/{id}/records returns the exact records with their current
status. Every value points at a Postbox-owned name, never at a third-party
hostname, so your customers never see another provider in their DNS. It also
means the records behind them can be rotated without you editing DNS again.
For mail.acme.com the set looks like this:
| Type | Host | Value | Purpose |
|---|---|---|---|
TXT | _postbox.mail.acme.com | pb-verify=<token> | Ownership |
CNAME | <selector>._domainkey.mail.acme.com | dk.<slug>.dns.postboxapp.cloud | DKIM signing |
CNAME | send.mail.acme.com | mf.<slug>.dns.postboxapp.cloud | MAIL FROM alignment |
MX | mail.acme.com | mx.postboxapp.cloud (priority 10) | Inbound, only if receivingEnabled |
TXT | _dmarc.mail.acme.com | v=DMARC1; p=quarantine; … | DMARC, optional |
Flattened CNAMEs are accepted, so providers that flatten at the apex will still verify.
Verify
Publish the records, then trigger a check rather than waiting for one:
const result = await pb.domains.verify(domainId);result = pb.domains.verify(domain_id)var result = await pb.Domains.VerifyAsync(domainId);var result = pb.domains.verify(domainId);result, err := pb.Domains.Verify(ctx, domainId)curl -X POST https://api.postboxapp.cloud/v1/domains/$DOMAIN_ID/verify \
-H "Authorization: Bearer $PB_KEY" -H "X-Project-Id: $PROJECT_ID"The response carries a checks object:
{
"success": true,
"data": {
"id": "dom_...",
"domain": "mail.acme.com",
"status": "active",
"region": "eu-west-1",
"receivingEnabled": true,
"checks": {
"ownership": true,
"dkim": true,
"mailFrom": true,
"receiving": true,
"dmarc": false
}
}
}Activation requires ownership, DKIM, and MAIL FROM. Those three and no more.
receivingonly matters if you asked for inbound. It does not gate sending.dmarcis reported but never gates activation. A domain activates withdmarc: false. We surface it because DMARC materially helps your deliverability, not because we require it. See Deliverability for how to roll a DMARC policy out safely.
DNS propagation is the usual culprit for a failed check. Verification is safe to re-run as often as you like; each pass also self-heals the records Postbox hosts on its side.
Sending requires an active domain
POST /messages/send refuses to send from a domain that is not active. This
is deliberate. Sending from an unverified domain is how a shared sending
reputation gets destroyed, so the check is not optional and cannot be bypassed.
The first time a domain activates, domain.dns.verified fires on your webhooks
and event stream.
Delete
await pb.domains.delete(domainId);pb.domains.delete(domain_id)await pb.Domains.DeleteAsync(domainId);pb.domains.delete(domainId);_, err := pb.Domains.Delete(ctx, domainId)curl -X DELETE https://api.postboxapp.cloud/v1/domains/$DOMAIN_ID \
-H "Authorization: Bearer $PB_KEY" -H "X-Project-Id: $PROJECT_ID"This tears down the records Postbox hosts and the provisioning behind them. Mail already stored in mailboxes on that domain is not deleted by this call.