Sending domains
Register your own sending domain with a supported email provider, publish DKIM/SPF/DMARC records (manually or auto-injected via your DNS provider), verify, and set a default.
Sending domains
To send email from your own domain — and to authenticate that mail so it passes
SPF, DKIM, and DMARC — register the domain with a supported email provider from
/v1/integrations/sending-domains. The flow provisions the domain at the
provider, hands you the DNS records to publish, and verifies them. All routes
require admin or owner role and the email module.
Supported providers
The provider is chosen per domain via provider_kind. Pact ships domain adapters
for five providers (core/email/factory.py):
resendsendgridpostmarkmailgunses(Amazon SES)
Bring your own provider credentials
Provider credentials are tenant-scoped and configured through the integrations
UI — they are never entered in the domain request body. If no credential is
found for the chosen provider_kind, the create call returns a 422.
Register a domain
POST /v1/integrations/sending-domains
{
"domain": "mail.acme.com",
"provider_kind": "resend",
"tracking_subdomain": "track.acme.com" // optional
}
Pact calls the provider's create_sending_domain, persists the row (with the
DKIM selector, SPF and DMARC records), and returns the domain plus a
dns_records array — the exact DNS entries to publish. Each record carries a
type, host, value, ttl, optional priority, and a purpose
(dkim, spf, dmarc, bounce_mx). Registering the same domain twice returns
a 409.
GET /v1/integrations/sending-domains → list domains for the tenant
GET /v1/integrations/sending-domains/{id} → one domain
Publish DNS: manual or auto-inject
Publish the returned records at your DNS host by hand, or let Pact write them for
you if your DNS provider is one of the supported ones (core/integrations/dns/factory.py):
dns_cloudflaredns_route53
POST /v1/integrations/sending-domains/{id}/inject-dns
{ "dns_provider_kind": "dns_cloudflare" }
Pact fetches the current DNS records from the email provider, filters out
placeholder/<your-domain> entries, and upserts the actionable DKIM/SPF/DMARC
records into your zone. The response reports the zone, the number of records
upserted, and any per-record errors. This too requires a tenant-scoped DNS
credential.
Verify
POST /v1/integrations/sending-domains/{id}/verify
Pact polls the provider for the domain's current status and updates the stored
row. A first successful verification writes an email.domain.verified audit
event; a failure writes email.domain.failed with the provider error. The
response echoes the latest status and DNS records so the UI can show which
records are still missing.
Set a default and delete
POST /v1/integrations/sending-domains/{id}/set-default
DELETE /v1/integrations/sending-domains/{id}
Only a verified domain can be set as default (otherwise 409). The default
domain cannot be deleted until another is promoted — you must always have a
sending identity. Every mutation is audited (email.domain.created,
email.domain.set_default, email.domain.dns_injected, and so on).
Order of operations
Register → publish DNS (inject or manual) → verify → set default →
then promote deliverability to full_prod. The promotion checklist
explicitly asks you to confirm DNS is verified first.