Gmail Bulk Sender Requirements: A Build-and-Verify Playbook
Cross 5,000 messages to Gmail addresses in a day and you are a bulk sender forever, judged on three pass/fail gates: aligned authentication, spam rate, and RFC 8058 one-click unsubscribe. Here are the exact records, headers, and dig commands that separate a domain Gmail trusts from one it silently spam-folders.
EvilMail TeamJuly 12, 202612 min read
The number that matters is 5,000. Send more than 5,000 messages to Gmail addresses in any 24-hour window and Gmail flips a bit on your sending domain: you are a bulk sender now, and you stay one. There is no cool-down that walks it back. From that moment you are graded on three pass/fail axes — authentication with alignment, spam rate, and RFC 8058 one-click unsubscribe — and failing any single one does not bounce your mail. It spam-folders it. That distinction is the whole problem: a bounce is a signal you can act on; a silent inbox-to-spam demotion gives you nothing but a slowly dying open rate.
The myth to kill first: "we set up SPF and DKIM, we're fine." You are not fine. Bulk senders need SPF and DKIM and DMARC, and — the part that quietly sinks most setups — the authentication has to *align* with the visible From: domain. Passing SPF and passing DKIM while failing alignment is a real, common state, and Gmail treats it as a DMARC failure. Below is how to build it so it aligns, and how to prove it with dig, swaks, and curl before you ever push volume.
The three gates, and how Gmail actually scores them
Think of it as three independent pass/fail checks stacked in front of the inbox:
Authentication. SPF, DKIM, and DMARC must all be present, and DMARC must *pass* — which means at least one of SPF or DKIM has to be aligned to your From: domain. A p=none DMARC policy is enough to clear this gate.
Spam rate. Reported in Google Postmaster Tools as messages users mark as spam divided by the messages Gmail delivers to the inbox. The hard ceiling is 0.3%. Touch it and you get parked in spam for weeks.
One-click unsubscribe. RFC 8058: the List-Unsubscribe header plus List-Unsubscribe-Post, backed by an https endpoint that honors an unauthenticated POST.
Underneath all three sit the table stakes nobody credits you for but everyone loses on: a valid PTR / reverse DNS record on your sending IP that resolves forward to the same name, TLS on the SMTP connection, a valid RFC 5322 From:, and exactly one From: address. Miss reverse DNS and you can fail before the authentication checks even run.
One clarification that saves arguments: the 5,000 count is per day and only counts mail *destined for Gmail addresses*. Your total send volume is irrelevant — 4,000 to Gmail and 90,000 to everyone else keeps you under the bulk threshold at Gmail. But once you cross it, assume the status is permanent and build for it.
Authentication that aligns, not just passes
Start with the three records. Here is a real, coherent set for a domain that signs its own mail:
dns
; SPF — envelope-from / Return-Path domain
example.com. IN TXT "v=spf1 include:_spf.yourmail.com -all"
; DKIM — 2048-bit RSA public key (truncated)
sel1._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA..."
; DMARC — minimum to pass Gmail's gate, relaxed alignment
_dmarc.example.com. IN TXT "v=DMARC1; p=none; rua=mailto:[email protected]; adkim=r; aspf=r"
Three decisions inside those records earn their keep:
`-all` vs `~all` on SPF.~all is softfail — "probably not us, but deliver anyway." -all is hardfail — "if it's not on this list, it isn't us." Ship ~all while you're still discovering which services send as you, then tighten to -all the moment your list is complete. Leaving ~all in place forever is leaving the front door unlatched.
2048-bit DKIM, not 1024. 1024-bit keys are deprecated, and a growing share of receivers ignore or distrust them. Generate 2048-bit RSA. If your DNS provider chokes on the long TXT value, split it into quoted strings — resolvers concatenate them.
`p=none` is the floor, not the goal.p=none passes Gmail's authentication gate and protects nothing — it tells the world "monitor, but honor spoofed mail anyway." It exists so you can collect rua aggregate reports and confirm alignment before you enforce. Once your legitimate streams pass cleanly, move to p=quarantine and then p=reject. That progression is the actual anti-spoofing work; passing Gmail's gate is a side effect.
Now the part everyone misses. DMARC passes only if the domain that authenticated aligns with the From: header domain. Two independent paths:
SPF alignment compares the Return-Path / envelope-from domain to the From: domain.
DKIM alignment compares the signature's d= value to the From: domain.
Relaxed (r) alignment accepts an organizational-domain match — mail.example.com aligns with example.com. Strict (s) demands an exact match. Relaxed is the sane default.
Lean on DKIM alignment, not SPF alignment. When your mail is forwarded — mailing lists, .forward files, corporate relays — the envelope-from gets rewritten to the forwarder's domain, and SPF alignment collapses. The DKIM signature travels with the message body and keeps validating. A setup that passes DMARC only via SPF looks healthy in your own tests and quietly fails the instant a recipient forwards. Sign with a d= that matches your From: organizational domain and you survive the hop.
Verifying alignment before you send at scale
Never trust a DNS record you haven't queried from outside. Confirm all four with dig:
The load-bearing detail is dkim=pass header.d=example.com, where header.d=matches the From: domain. If dkim=pass but header.d= shows your ESP's domain instead of yours, you are passing DKIM and failing alignment — exactly the trap. For a second opinion and a score, mail-tester.com gives you a 10-point breakdown, and Google Postmaster Tools (postmaster.google.com) shows domain and IP reputation plus the spam-rate dashboard — but you must add its DNS TXT verification record first to unlock it. Connect Postmaster before your first bulk send, not after something breaks.
Keeping spam rate under the line
The ceiling is 0.3%. Defend 0.1%. The metric is user "report spam" clicks divided by the messages Gmail delivers to the inbox. The gap between 0.1% and 0.3% is your entire margin of safety, and the ceiling doubles as a spike detector — one bad campaign that briefly touches 0.3% can park the domain in spam for weeks, long after the numbers recover.
The levers that actually move it:
List hygiene. Purge hard bounces and dead addresses. Sending to a decayed list is the fastest route to spam complaints and spam-trap hits.
Honor unsubscribes immediately. A user who unsubscribed and still gets mail hits "report spam" instead — and that costs far more than the lost address.
Segment cold from engaged. Blasting people who haven't opened in a year drags your whole reputation down. Mail your engaged core more, your cold list rarely and carefully.
Warm up new IPs and domains. Reputation is earned in a ramp, not claimed. Start low, grow daily.
Never spike volume. A flat sender that suddenly 10x's looks exactly like a compromised account. Ramp; don't jump.
RFC 8058 one-click unsubscribe done right
A bare List-Unsubscribe header no longer satisfies Gmail. You need the pair, and you need an endpoint that behaves:
When both headers are present, Gmail renders a native Unsubscribe link beside the sender name. When the user clicks it, Gmail sends an HTTP POST to your https URL with the body List-Unsubscribe=One-Click. That POST arrives with no cookies, no auth, no session, and Gmail does not follow redirects. Your endpoint must return 200, suppress the address within 2 days, and require no landing page, no login, and no confirmation click.
The bug that fails this gate silently: your unsubscribe endpoint 302-redirects to a "you've been unsubscribed" page, or expects a logged-in session. Gmail reads that redirect or auth challenge as failure and stops showing the one-click link — dropping you back to the old, worse experience that drives "report spam" clicks. Keep the mailto fallback for clients that only support the legacy header, but the https POST is what Gmail grades.
Test it exactly the way Gmail will, from a machine with no session cookie:
bash
curl -i -X POST -d 'List-Unsubscribe=One-Click' https://example.com/u/abc123
You want HTTP/2 200, no Location: redirect header, and the address suppressed on the backend. Anything else is a failure you can fix now instead of discovering in your spam rate later.
Pre-send checklist
Run this before every scaled campaign, not once at setup:
SPF present and tightened to -all once your senders are known.
DKIM present, 2048-bit RSA, and dkim=pass in Authentication-Results.
DKIM `header.d=` matches the From: domain — alignment, verified in Show original.
DMARC published at _dmarc, at least p=none with a working rua.
PTR / reverse DNS set and resolving forward to the same hostname.
TLS enforced on outbound SMTP.
`List-Unsubscribe` + `List-Unsubscribe-Post` headers both present, with an https URL.
Unsubscribe endpoint returns 200 to an unauthenticated POST, no redirect, suppresses within 2 days — confirmed with curl.
Postmaster Tools connected and verified.
Spam-rate baseline under 0.1%, and volume ramped, never spiked.
The gates do not relax after you pass them. Reputation is a rolling measurement, and a domain that cleared every check in January can be spam-foldered in March because a purchased list slipped into one campaign or a DKIM key rotation broke alignment for a weekend. Check Postmaster Tools weekly, watch the spam-rate line the way you watch error rates on a production service, and treat any authentication change as a deploy that ships with a verification step. That discipline — not the initial setup — is what keeps a bulk sender in the inbox.