Postbox docs

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
      }'
FieldRequiredNotes
domainyesLowercased automatically.
regionnoThe sending region. Pinned at registration and not changeable afterward.
receivingEnablednoAdds 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:

TypeHostValuePurpose
TXT_postbox.mail.acme.compb-verify=<token>Ownership
CNAME<selector>._domainkey.mail.acme.comdk.<slug>.dns.postboxapp.cloudDKIM signing
CNAMEsend.mail.acme.commf.<slug>.dns.postboxapp.cloudMAIL FROM alignment
MXmail.acme.commx.postboxapp.cloud (priority 10)Inbound, only if receivingEnabled
TXT_dmarc.mail.acme.comv=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.

  • receiving only matters if you asked for inbound. It does not gate sending.
  • dmarc is reported but never gates activation. A domain activates with dmarc: 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.