PPactDocs
Administration

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):

  • resend
  • sendgrid
  • postmark
  • mailgun
  • ses (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

code
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.

code
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_cloudflare
  • dns_route53
code
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

code
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

code
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.