Skip to main content

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. See OWNERS.md for 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​

MechanismStateNotes
DKIMβœ… passd=h852.work s=google β€” Workspace DKIM enabled & signing on egress. See dkim-key-rotation.md.
DMARCβœ… passp=NONE published; passes via DKIM alignment.
SPF❌ softfailSPF 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:

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

  1. Exactly one SPF (v=spf1) TXT record per domain. If one already exists, merge include:_spf.google.com into it β€” do not add a second v=spf1 record (multiple SPF records = permerror, worse than softfail).
  2. Keep ~all (softfail) until verified, then optionally tighten to -all (hardfail) once you're certain all legitimate mail for the domain flows through Google.
  3. SPF lookups are capped at 10 DNS lookups β€” include:_spf.google.com is 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.