Deliverability
The three-state email send guard, per-recipient allowlist, blocked-send log, test sends, and the promotion checklist that unlocks full production sending.
Deliverability
Pact protects your sender reputation with a pre-send deliverability guard that
sits in front of every non-transactional email. It is a three-position, per-tenant
state machine backed by tenants.email_send_state, enforced in
core/email/deliverability_guard.py and administered from
/v1/admin/email/deliverability.
Why the guard exists
A brand-new sending domain with no warmup can get a whole tenant's mail classified as spam. The guard defaults to the most conservative state so nothing but essential transactional mail leaves until an operator has verified DNS and reviewed sender reputation.
The three states
| State | Behavior |
|---|---|
essential_only (default) | Only kinds in ESSENTIAL_KINDS are sent. Everything else is blocked. |
limited_prod | Essential mail plus cap-gated sends to allowlisted addresses. |
full_prod | All sends allowed. Caps still log but do not block. |
Essential kinds always bypass the guard regardless of state — user_invite,
password_reset, mfa_enrollment, mfa_recovery_codes, billing_receipt,
billing_dunning, tenant_owner_alert, and a few more defined in the
ESSENTIAL_KINDS frozenset. A password reset always goes out even in
essential_only.
In limited_prod, sends are additionally capped by a sliding window shared with
the tenant rate-limit system: a per-recipient daily cap, a per-domain hourly cap
(major consumer domains such as gmail.com, outlook.com, yahoo.com,
icloud.com get their own bucket), and a per-tenant daily cap. Anything over cap
is blocked and logged.
There is also a deployment-wide kill switch: setting EMAIL_GLOBAL_OFF=true
blocks all non-essential sends across every tenant.
Fail-open by design
If the guard hits a database or Redis error while checking a send, it returns
allowed=True rather than silently dropping legitimate mail. Infrastructure
hiccups never cost you a real email — but state reads fail closed to
essential_only.
Read and set state
GET /v1/admin/email/deliverability → current guard state
PATCH /v1/admin/email/deliverability/state → { "state": "limited_prod" }
Both require admin or owner role. State changes write an
email.deliverability.state_changed audit event with the old and new state.
Allowlist
In limited_prod, only allowlisted recipients receive non-essential mail.
Manage the list at:
GET /v1/admin/email/deliverability/allowlist
POST /v1/admin/email/deliverability/allowlist → { "email": "...", "label": "..." }
DELETE /v1/admin/email/deliverability/allowlist/{entry_id}
Each entry is validated against a strict email pattern and every add/remove
emits an audit event (allowlist_added / allowlist_removed).
Blocked-send log
GET /v1/admin/email/deliverability/blocked-log?limit=100
Returns recently blocked sends from email_send_blocked_log. Recipients are
stored hashed (PII-safe) with the block reason (tenant_essential_only,
cap reasons, env_global_off) so you can see exactly what the guard is
holding back.
Test send
Before promoting, verify a real delivery end-to-end:
POST /v1/admin/email/deliverability/test-send
{ "recipient": "[email protected]", "subject": "...", "body_text": "...", "confirmed": true }
confirmed must be true — an explicit acknowledgment that you intend a real
send. The response reports delivered, provider, message_id, and any
error, and the attempt is audited.
Promotion checklist
Moving to full_prod is gated behind an explicit four-item checklist:
POST /v1/admin/email/deliverability/promote
{
"dns_verified": true, // SPF/DKIM/DMARC confirmed
"reputation_checked": true, // Google Postmaster / SNDS reviewed
"consent_confirmed": true, // consent records confirmed for the audience
"audit_archived": true // pre-send audit reviewed and archived
}
Every field must be acknowledged or the request is rejected with a 422 listing
what is missing. Promotion writes an email.deliverability.promoted_full_prod
audit event capturing all four acknowledgments.
Operations dashboard
A read-only reporting surface lives under the same prefix for monitoring in-flight deliverability:
GET /v1/admin/email/deliverability/dashboard → headline metrics
GET /v1/admin/email/deliverability/domains → per-domain stats
GET /v1/admin/email/deliverability/ips
GET /v1/admin/email/deliverability/recipients
GET /v1/admin/email/deliverability/issues