Runbook: Email SPF Deliverability (softfail β pass)
P1 when conversation email lands in spam. Outbound Specialist email is sent as the per-OSA Google Workspace mailbox via the Gmail API (DWD). DKIM and DMARC are configured and passing, but the SPF record for the Workspace domains does not authorize Google's sending IPs, so receivers see
spf=softfail. Combined with a new sending domain this is a real spam-placement signal. Fix is a one-line DNS change per domain in Cloudflare. SeeOWNERS.mdfor on-call.
Env mapping (per #1537): h852.work = dev, h853.work = staging, h.work = prod.
Symptomβ
Client reports Specialist replies landing in spam / junk, or "looks untrusted". The message body and threading are fine; the problem is sender authentication.
Evidence (observed on a real reply, 2026-07-06)β
Authentication-Results on a reply delivered from a @h852.work mailbox to an external Gmail account:
dkim=pass header.i=@h852.work header.s=google β
dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=h852.work β
spf=softfail (google.com: domain of transitioning {alias}@h852.work
does not designate 209.85.220.41 as permitted sender)
smtp.mailfrom={alias}@h852.work β
209.85.220.41 is a Google outbound mail server (mail-sor-f41.google.com). The domain's SPF record is present but uses ~all (softfail) without include:_spf.google.com, so Google's own sending IP is not authorized β hence softfail. Google's "domain of transitioning β¦" wording is exactly this: an SPF record exists but doesn't cover the sender.
Root causeβ
We send as the Workspace mailbox through the Gmail API (DWD). The envelope sender is {alias}@h852.work, so SPF is evaluated against the h852.work SPF record β which must authorize Google. It currently does not.
DNS for these domains is managed externally in Cloudflare (Terraform creates no DNS records β see infra/terraform/modules/alb/main.tf header comment), so this fix is a Cloudflare change, not a code or Terraform change.
Current authentication stateβ
| Mechanism | State | Notes |
|---|---|---|
| DKIM | β pass | d=h852.work s=google β Workspace DKIM enabled & signing on egress. See dkim-key-rotation.md. |
| DMARC | β pass | p=NONE published; passes via DKIM alignment. |
| SPF | β softfail | SPF record does not include:_spf.google.com. This runbook fixes this. |
Fix β publish a Google-authorizing SPF record (Cloudflare)β
Add / update the apex TXT SPF record for each sending domain:
| Domain | Type | Name | Value |
|---|---|---|---|
h852.work (dev) | TXT | @ | v=spf1 include:_spf.google.com ~all |
h853.work (staging) | TXT | @ | v=spf1 include:_spf.google.com ~all |
h.work (prod) | TXT | @ | v=spf1 include:_spf.google.com ~all |
Rules:
- Exactly one SPF (
v=spf1) TXT record per domain. If one already exists, mergeinclude:_spf.google.cominto it β do not add a secondv=spf1record (multiple SPF records =permerror, worse than softfail). - Keep
~all(softfail) until verified, then optionally tighten to-all(hardfail) once you're certain all legitimate mail for the domain flows through Google. - SPF lookups are capped at 10 DNS lookups β
include:_spf.google.comis one; don't stack many includes.
Verifyβ
# 1. Record is published and single
dig +short TXT h852.work | grep spf1 # exactly one v=spf1 line, contains include:_spf.google.com
# 2. Send a test to https://www.mail-tester.com and confirm SPF = pass (aim 10/10)
# 3. Google Postmaster Tools β the domain β "SPF success rate" trends to ~100%
On a fresh inboundβreply round-trip, the recipient's Authentication-Results should now read spf=pass alongside the already-passing dkim=pass / dmarc=pass.
Follow-ups (out of scope here)β
- DMARC enforcement ramp:
p=noneβp=quarantineβp=reject, watching aggregate (rua) reports at each step. Tracked separately β this runbook only removes the SPF softfail. - Content hygiene (multipart/alternative HTML part, etc.) is a minor, separate lever β not the cause of the softfail.
Relatedβ
dkim-key-rotation.mdβ DKIM key lifecycle for the same domains.dns-mx-rollback.mdβ DNS/MX change safety.docs/features/channels.mdβ Gmail API + DWD outbound architecture.