guides
Meeting Gmail and Yahoo bulk sender requirements
May 10, 2026

Your campaign used to land fine. Then one morning Gmail starts deferring it with a
421and Yahoo bounces a chunk of it outright. Nothing in your content changed. What changed is that you crossed 5,000 messages a day and the bulk sender rules now apply to you.
If you send more than 5,000 messages a day to Gmail or Yahoo, you must do three things or your mail gets blocked: authenticate every message with SPF, DKIM, and DMARC (with domain alignment), support RFC 8058 one-click unsubscribe, and keep your spam complaint rate under 0.3 percent. These are not best-practice suggestions anymore. Since the rules took effect in February 2024, mail that fails them is rejected at the SMTP layer or filed straight to spam, and the failure is silent unless you read the bounce codes.
This guide is the checklist, in the order you should implement it, with the exact DNS records, headers, and thresholds. It is honest about which parts are tedious (the unsubscribe POST endpoint is the one people get wrong) and which are a five-minute DNS edit. At the end I will show how a Cloudflare-native stack ships these defaults so you are compliant on day one, but the checklist works no matter what you send through.
What are the Gmail and Yahoo bulk sender requirements?
Bulk senders must authenticate their mail, offer one-click unsubscribe, and keep complaints low. Concretely, the three requirements are:
- Authentication and alignment. Every message must pass SPF and DKIM, and your from-domain must publish a DMARC record (minimum
p=none). Your mail must pass DMARC alignment, meaning the SPF domain or the DKIMd=domain matches the domain in the visibleFromheader. - Easy unsubscribe. Marketing and bulk mail must include RFC 8058 one-click unsubscribe headers, and you must honor the unsubscribe within two days.
- Low complaint rate. Your spam complaint rate, as reported in Google Postmaster Tools, must stay under 0.3 percent, and you should target under 0.1 percent.
The trigger is volume. Google treats you as a bulk sender once you send close to or more than 5,000 messages to Gmail addresses in any 24-hour window. The count is per from-domain (subdomains included), and once you cross it you are a bulk sender from then on. Yahoo enforces an equivalent policy without naming an exact number, so treat the 5,000/day line as the threshold for both. Microsoft (Outlook, Hotmail) announced matching requirements that phase in through 2025, so building to the Gmail and Yahoo bar makes you compliant across the three providers that handle most consumer mail.
A useful mental model: the providers put up a pass/fail gate in front of the reputation curve. Fail the gate and your reputation score never gets a chance to matter, because the mail does not get scored at all.
How do I authenticate mail to pass the bulk sender rules?
Publish SPF, DKIM, and DMARC DNS records, and make sure at least one of SPF or DKIM aligns with your From domain. Authentication that passes but does not align still fails DMARC, which is the single most common reason senders think they are compliant when they are not.
Start with the three DNS records on your sending domain:
; SPF: authorize the source that sends your bulk mail
example.com. TXT "v=spf1 include:_spf.yoursender.example -all"
; DKIM: publish the public key your messages are signed with
s1._domainkey.example.com. TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4..."
; DMARC: a record must exist; p=none is enough to pass the requirement
_dmarc.example.com. TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.com; fo=1"
Now the part that trips people up. Passing is not the same as aligning. SPF passes when the sending IP is authorized by the Return-Path (envelope) domain. DKIM passes when the signature verifies against the d= domain. DMARC passes only when one of those domains aligns with the domain in the From: header that the recipient sees.
Here is a failure that looks fine in a quick test. Suppose your From is news@example.com, but you send through a provider that sets the Return-Path to bounces@sender-platform.net and signs DKIM with d=sender-platform.net. SPF passes (the platform's domain authorizes its IPs) and DKIM passes (the platform's key verifies), so a naive check reports "all green." But neither aligns with example.com, so DMARC fails, and Gmail rejects the message under the bulk sender rules.
Verify alignment by reading the Authentication-Results header on a message you actually received at Gmail:
Authentication-Results: mx.google.com;
spf=pass (google.com: domain of bounces@example.com) smtp.mailfrom=example.com;
dkim=pass header.d=example.com;
dmarc=pass (p=NONE) header.from=example.com
You want dmarc=pass and header.from matching the header.d (DKIM) or the smtp.mailfrom (SPF) domain. If dmarc=fail shows up even though spf=pass and dkim=pass, you have an alignment problem, not an authentication problem. The fix is either to sign DKIM with your own domain (most providers let you publish a CNAME so the d= is yours) or to use a custom Return-Path subdomain on your domain.
The record-by-record details, including how to pick a DKIM selector and set up a custom Return-Path, are in the SPF, DKIM, and DMARC setup guide, and you can confirm the whole chain passes at a real receiver with the method in how to check SPF, DKIM, and DMARC are actually passing.
Do I need DMARC, and what policy is enough?
You need a DMARC record, but p=none is enough to satisfy the requirement. The rule is that the record must exist and your mail must pass DMARC alignment; the policy value (none, quarantine, or reject) does not have to enforce anything to clear the bar.
This is deliberately a low bar so that senders are not forced into an aggressive policy before they have read their reports. But there is a catch worth knowing: p=none means you have published a record and you are alignment-passing, which is all Gmail and Yahoo check. It does not protect your domain from spoofing, and it does not improve your placement beyond passing the gate.
The sensible path is to start at p=none to satisfy the requirement immediately, read a few weeks of aggregate reports to confirm all of your legitimate sending sources align, then tighten to quarantine and eventually reject:
; Step 1: satisfy the requirement and start collecting reports
_dmarc.example.com. TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.com; fo=1"
; Step 2 (weeks later, after reports are clean): start quarantining failures
_dmarc.example.com. TXT "v=DMARC1; p=quarantine; pct=100; rua=mailto:dmarc@example.com"
; Step 3: full enforcement once you are confident
_dmarc.example.com. TXT "v=DMARC1; p=reject; rua=mailto:dmarc@example.com"
Do not jump straight to p=reject. If you have a forgotten sending source (a CRM, a billing system, a help desk) that is not aligned, reject will silently bin its mail. Read the aggregate reports first. The mechanics of reading those XML reports without a paid tool are covered in the email deliverability guide.
How do I implement one-click unsubscribe correctly?
One-click unsubscribe requires two headers and a working POST endpoint. The headers tell the mailbox provider to render an Unsubscribe button; the endpoint is what removes the recipient when they click it. Most senders add the headers and forget the endpoint, which fails the requirement the moment a provider tests it.
Add both headers to every bulk message:
List-Unsubscribe: <https://example.com/u/8f3a2c91>, <mailto:unsubscribe@example.com>
List-Unsubscribe-Post: List-Unsubscribe=One-Click
The List-Unsubscribe header must include an https URL (the mailto is optional but good to keep). The List-Unsubscribe-Post header must be exactly List-Unsubscribe=One-Click. The presence of that second header is what tells the provider to use the POST flow rather than just opening the link in a browser.
When the recipient clicks Unsubscribe in Gmail or Yahoo, the provider sends an HTTP POST to your https URL with that form body. Your endpoint must accept it, suppress the recipient, and return success, without requiring a login or showing a confirmation page. A minimal handler:
// POST /u/:token -> one-click unsubscribe endpoint
export async function handleUnsubscribe(request, env) {
// RFC 8058 sends application/x-www-form-urlencoded with List-Unsubscribe=One-Click
const body = await request.text();
if (!body.includes("List-Unsubscribe=One-Click")) {
return new Response("Bad request", { status: 400 });
}
const token = new URL(request.url).pathname.split("/").pop();
const subscriber = await env.DB.prepare(
"SELECT email FROM subscribers WHERE unsub_token = ?",
).bind(token).first();
if (!subscriber) {
// Return 200 anyway: never leak whether a token is valid
return new Response("OK", { status: 200 });
}
await env.DB.prepare(
"UPDATE subscribers SET status = 'unsubscribed', unsubscribed_at = ? WHERE email = ?",
).bind(Date.now(), subscriber.email).run();
return new Response("OK", { status: 200 });
}
Three rules that the spec enforces and that providers check:
- No authentication. The POST arrives from the provider's servers, not the user's browser session. If your endpoint requires a login, the unsubscribe silently fails and your complaint rate climbs (people who cannot unsubscribe hit report-spam instead).
- Honor it within two days. Suppress the address quickly. The two-day window is in the requirement; treat it as "immediately" and you are safe.
- Use a per-recipient token, not the email in the URL. Putting the raw email in the unsubscribe URL leaks addresses and lets anyone unsubscribe anyone. Use an opaque token mapped to the subscriber.
The unsubscribe link in your footer is separate and still allowed, but it does not satisfy the requirement on its own; you need the headers and the POST endpoint. The full header-and-POST walkthrough, including how to generate and rotate tokens, is in implementing one-click unsubscribe and List-Unsubscribe headers.
What spam complaint rate do I need to stay under?
Keep your spam complaint rate under 0.3 percent, and target under 0.1 percent. The rate is measured in Google Postmaster Tools as the fraction of delivered messages where the recipient clicked report-spam. At or above 0.3 percent, Gmail starts throttling and then rejecting your mail; the gap between 0.1 and 0.3 is your safety margin, not your target.
This is the one requirement you cannot fix with a config change, because it is a behavioral signal. You drive it down by sending wanted mail to people who asked for it:
- Set up Google Postmaster Tools on day one. It is free and it is the only place you see the complaint rate Gmail actually uses to judge you. Without it you are flying blind; you will not know you crossed 0.3 percent until delivery has already degraded.
- Honor unsubscribes instantly. Every recipient who wants out and cannot get out is a future complaint. A working one-click flow is the single biggest lever on complaint rate.
- Do not mail stale or purchased lists. A list you have not touched in a year is the fastest way to spike complaints on a bulk-sending domain. Send to recently engaged recipients and let the inactive ones age off.
- Separate marketing from transactional. A bad campaign should not be able to push your receipts and password resets over the threshold. More on that below.
If your complaint rate is already high, the recovery is the same discipline as a warmup: pull volume back, send only to your most engaged segment, and rebuild. The ramp mechanics are in how to warm up a new email sending domain.
Should transactional and marketing mail be separated to meet these rules?
Yes, separate them onto different subdomains. The bulk sender rules apply to a from-domain, so a marketing campaign that earns complaints on example.com drags down the reputation that delivers your password resets from the same domain. Splitting the streams isolates the risk.
The standard pattern is marketing from news.example.com or e.example.com and transactional from mail.example.com, each with its own DKIM key and its own DMARC alignment. The one-click unsubscribe requirement only applies to the marketing stream (you do not put an unsubscribe header on a password reset), and the complaint dynamics are entirely different, so keeping them on separate domains means each stream is judged on its own behavior. The full reasoning, including the engagement and reputation differences, is in why you separate transactional and marketing sending.
One more trap: do not run cold outreach from a domain that also sends bulk marketing. Cold email generates complaints by design, and a complaint spike on a bulk-sending domain is exactly what trips the 0.3 percent ceiling. Cold outreach belongs on a separate, disposable domain.
The full bulk sender checklist
Before your next bulk send, confirm all of these:
- SPF record published and passing.
- DKIM signing enabled, with the
d=domain alignable to yourFromdomain. - DMARC record published (minimum
p=none) and your mail passes DMARC alignment, verified in a realAuthentication-Resultsheader. -
List-Unsubscribeheader with anhttpsURL on all marketing mail. -
List-Unsubscribe-Post: List-Unsubscribe=One-Clickheader present. - Unsubscribe POST endpoint live, requires no login, suppresses within two days, uses opaque tokens.
- Google Postmaster Tools configured, complaint rate under 0.3 percent (target under 0.1).
- Valid
Message-ID,Date, and matchingFromheaders (the formatting basics the rules also require). - Transactional and marketing on separate subdomains.
If every box is checked, you clear the gate at Gmail, Yahoo, and Microsoft.
Or skip the checklist: ship the defaults
Everything above is a one-time setup plus an ongoing discipline. The DNS records you publish once. The unsubscribe endpoint and the token mapping you build once and then maintain. The complaint rate you watch forever. It is all doable by hand, and if you send through any provider it is worth doing correctly, because the gate does not care how you got there.
Tinbox is a self-contained email stack you deploy onto your own Cloudflare account: D1 for storage, R2 for attachments, Queues for sending. It is built to clear the bulk sender gate by default. The campaign sender attaches the List-Unsubscribe and List-Unsubscribe-Post: List-Unsubscribe=One-Click headers to bulk mail and serves the RFC 8058 POST endpoint that suppresses the recipient, with per-recipient tokens, so the part most senders get wrong is wired for you. DKIM signs with your own domain, so DMARC alignment is correct out of the box, and the npx tinbox init flow walks you through the SPF, DKIM, and DMARC records before your first send. Running transactional and marketing on separate sending domains, the separation this guide recommends, is designed into the model, though multi-domain support is still being built out. And because there is no per-recipient pricing, keeping a clean, engaged list does not cost more than blasting a dirty one.
One honest caveat: Tinbox cannot lower your complaint rate for you. It gives you a working unsubscribe flow and surfaces the deliverability signals, but the 0.3 percent ceiling is a function of who you mail and how often, and that part is still your discipline. The checklist above still applies; the stack just ships the mechanical half of it.
Deploy this yourself: npx tinbox init example.com. The deploy sets up authentication and the one-click unsubscribe endpoint before your first bulk send, so you start compliant. See the docs for campaign sending and per-stream domain configuration.
Frequently asked questions
What are the Gmail and Yahoo bulk sender requirements?
Bulk senders (more than 5,000 messages per day to Gmail, any volume to a Yahoo address with the same scrutiny) must do three things: authenticate every message with SPF and DKIM and publish a DMARC record with at least p=none and DMARC alignment, support one-click unsubscribe per RFC 8058 with a List-Unsubscribe and List-Unsubscribe-Post header, and keep the spam complaint rate reported in Google Postmaster Tools under 0.3 percent. Mail that fails authentication or alignment is rejected; senders over the complaint threshold get throttled or blocked.
What counts as a bulk sender for Gmail?
Google defines a bulk sender as anyone sending close to or more than 5,000 messages to Gmail addresses within a 24-hour period. The count is per from-domain, including subdomains, and once you cross the threshold on any single day you are treated as a bulk sender going forward. Yahoo applies equivalent rules without publishing the exact number, so the safe assumption is that the 5,000/day line is the trigger for both.
Do I need DMARC to send bulk email to Gmail and Yahoo?
Yes. You must publish a DMARC record on your from-domain. The policy can be p=none (monitor only), so DMARC does not have to quarantine or reject anything to satisfy the requirement, but the record must exist and your mail must pass DMARC alignment: the SPF domain or the DKIM d= domain has to match the domain in your visible From header. A passing SPF or DKIM alone is not enough without alignment.
What is the spam complaint rate threshold for bulk senders?
Keep the spam complaint rate, as reported in Google Postmaster Tools, below 0.3 percent (three complaints per thousand messages), and ideally below 0.1 percent. At or above 0.3 percent Gmail begins throttling and then rejecting your mail. The rate is measured by recipients clicking the report-spam button, so it is driven by sending wanted mail to engaged recipients, not by content alone.
What is RFC 8058 one-click unsubscribe?
RFC 8058 defines one-click unsubscribe: the sender includes a List-Unsubscribe header with an https URL and a List-Unsubscribe-Post header with the value List-Unsubscribe=One-Click. The mailbox provider renders an Unsubscribe link in its UI, and when the user clicks it the provider sends an HTTP POST to your URL. You must process that POST and stop mailing the recipient within two days, without requiring a login or a confirmation page.
Does the one-click unsubscribe requirement apply to transactional email?
No. The one-click unsubscribe requirement applies to bulk and marketing mail, not to transactional messages like password resets, receipts, and one-time codes. But the authentication requirements (SPF, DKIM, DMARC alignment) apply to all mail from a bulk-sending domain. The cleanest setup keeps transactional and marketing on separate subdomains so the unsubscribe and complaint dynamics of marketing do not affect transactional delivery.


