Skip to main content

Gmail & Yahoo Bulk-Sender Requirements as a Compliance Posture

Google and Yahoo published a joint set of sender requirements in October 2023 and have enforced them for bulk senders — anyone above 5,000 messages per day — since February 2024. The regime is not a statute and not an Orbit policy: it is the acceptance policy of the two largest mailbox providers your email lands on, and a violation is answered with rejection, not merely spam-folder placement. Messages from a non-compliant bulk sender bounce at Gmail’s and Yahoo’s doors with a policy rejection, so the surface behaves like a compliance gate even though no law created it. The obligations are tenant-owned. Orbit verifies your domain and carries the headers, but the SPF/DKIM/DMARC records live in your DNS, the complaint rate is produced by your list, and the spam-rate floor is scored by Google Postmaster Tools against your sending domain. This page maps each obligation to the Orbit surface you read or configure it on, so a bulk sender can close the regime deliberately instead of discovering it in a rejection spike.
This page is guidance, not legal advice. The exposure here is not a fine — it is deliverability rejection at the recipient mailbox provider. The statutory layers that sit beside this regime (CAN-SPAM in the US, CASL in Canada, the Spam Act in Australia) specify content and consent rules and are documented on their own pages; nothing in this page replaces them.

The four obligations, mapped to Orbit surfaces

The 2024 regime has four mechanical requirements. For each: what the rule demands, and where the control lives in Orbit. Obligations 1 and 2 are DNS properties you publish and Orbit verifies; obligations 3 and 4 are traffic properties your send behaviour produces. The configuration sections below take them one at a time.

SPF + DKIM signing

The regime’s first obligation — authenticate with SPF and DKIM — is already a hard gate in Orbit: a custom sending domain does not accept traffic until its DNS verifies, and the DKIM p= public key is bit-length-validated (minimum 1,024 bits per RFC 8301), so a placeholder record never flips a domain to green. The records, the Verify DNS flow, and the drift-regression health check are covered in Email → Domain Setup; that page owns the mechanics and this page does not repeat them. The posture gap the bulk-sender regime closes is DMARC, which the Domain Setup table lists as one row among four. The next section is the policy guidance that row does not carry.

DMARC policy: p=none is the floor, not the posture

A DMARC record at _dmarc.your-domain.com must exist for Gmail and Yahoo to accept your bulk traffic, and p=none technically satisfies the checkbox. It is the wrong end-state. p=none tells receiver filters “monitor only — take no action on failures,” which means:
  • A domain that spoofs you fails nothing: the failed-DMARC mail in your recipients’ inboxes is indistinguishable from your own, and the reputation damage lands on your domain.
  • You are one DNS edit away from enforcement anyway when the next escalation of the regime raises the floor — Yahoo and Google have both signalled p=quarantine/p=reject as the intended direction.
The recommended posture is a staged ramp: publish v=DMARC1; p=none long enough to confirm your legitimate senders pass (SPF and DKIM aligned — with a receiver’s rua reports if you collect them), then step to p=quarantine, then p=reject. Each stage raises the penalty for spoofing you while your own authenticated traffic — which Orbit only sends once DKIM and SPF both verify — passes unchanged. Keep the DMARC record’s policy coherent with the rest of the row: a domain that fails its own DKIM/SPF checks and publishes p=reject rejects its own mail. Orbit’s verification gate makes that near-self- inflicted — verification is green before the domain accepts traffic, but an out-of-band edit to your DNS can drift it; the daily health check and the per-record traffic-light read below catch the drift before it becomes a rejection wave.

One-click unsubscribe (RFC 8058)

Every outbound email Orbit dispatches already carries the mechanism the regime names:
List-Unsubscribe (RFC 2369) names where the client should send the opt-out — an HTTPS URL plus a mailto fallback. List-Unsubscribe-Post (RFC 8058) is the signal the 2024 regime actually checks: it tells the mailbox provider it may POST to the header URL and the opt-out must complete without any further interaction — no confirmation page, no login wall, no second click. Orbit’s signed unsubscribe URL meets that contract: the POST lands at the unsubscribe endpoint, the token is verified, a suppression row is written with scope email, and an email.unsubscribed audit event is appended. The mailbox-provider “Unsubscribe” button and your in-body footer link resolve to the same endpoint, so the statutory layer (CAN-SPAM’s one-click requirement, CASL, the Spam Act) and the mailbox-provider regime are satisfied by the same mechanism — the framing this page adds. The in-body side is in US CAN-SPAM Compliance. Two points the regime adds beyond the statute:
  • The header pair is checked at the gate, not sampled. A bulk sender whose marketing mail lacks List-Unsubscribe-Post is rejected outright, not filtered; the header has to be present on every marketing message, which Orbit’s transport-layer injection guarantees by construction.
  • A mailto-only footer link no longer suffices. The in-body unsubscribe link remains required by CAN-SPAM and by the Gmail/Yahoo content rules, but the one-click POST property is header-side. Keep both: the footer link for the statute and your template, the header pair for the mailbox-provider gate.
What you control at send time is the in-body placement: keep an unsubscribe link in a shared footer block so every template carries it, and let the transport layer attach the headers.

Spam-rate thresholds

The numerical floor sits in Google Postmaster Tools, not in the statute and not in Orbit: Gmail publishes a per-domain spam rate (the share of your delivered mail recipients mark as spam), and the regime’s hard ceiling is 0.30% — cross it and bulk traffic is rejected. The healthy target is 0.10%; between the two you are accepting queued gunk, not compliance. The complaint-suppression layer is what keeps you under the ceiling:
  • A recipient’s “Report spam” click arrives on the delivery events path and writes a complaint suppression entry — the recipient is held out of later sends and cannot re-complain. See Email → Bounce and Complaint Handling for the lifecycle table.
  • GET /api/v1/email/suppressions/reputation reports the aggregate complaintRate over a trailing window next to the bounce rate, the health tier (healthy | at_risk | poor), and the current list size — poll it during ramp and while you test a new segment.
  • The consolidated deliverability overview surfaces the same complaint signal in the Email tab’s KPI row, and contact deliverability health reads it per contact and segment, so the propagation from a recipient’s spam-folder click to a segment-level verdict is observable without Postmaster Tools.
Orbit’s suppression of a complaining recipient keeps the same recipient from driving your rate up — it does not remove a complaint that already counted. The rate is scored by Google against your domain from recipient reports; Postmaster Tools is the measurement the regime enforces against, and the Orbit surfaces are what you watch between Postmaster check-ins. Cross-verifying both is the posture.

Posture configuration

Three concrete knobs close the regime end-to-end.

1. Read your DMARC posture from the DNS-status endpoint

The per-record traffic-light view reports the DMARC record’s health and its live value, so the policy you published is observable without a DNS lookup:
The dmarc entry in the records array carries both the status (valid | warning | invalid | unknown) and the recordActual string you actually published, e.g. { "kind": "dmarc", "status": "valid", "recordActual": "v=DMARC1; p=quarantine; ..." }. Read recordActual not only for presence but for the p= policy — that is the value the regime’s floor and the staged ramp above are about. The response format is in Email → Domain Setup.

2. Export the suppression ledger the complaint loop feeds

The suppression list that complaint events write is exportable as CSV or JSON, and the export run is itself audited — the trail an auditor or a deliverability consultant asks for. Both the ledger and its export are documented on consent-suppression-export; the email-side parameters (channel=email) filter the export to the rows the regime’s threshold is computed from.

3. Let the transport layer carry the header pair

You do not attach List-Unsubscribe or List-Unsubscribe-Post headers yourself; Orbit injects the signed URL and the one-click POST signal on every outbound message. What you control at send time is the in-body placement: keep an unsubscribe link in a shared footer block so every campaign template carries it, keep the physical postal address beside it for the CAN-SPAM layer, and send. The template and merge-tag layer resolves {{contact.unsubscribeUrl}} into the body at dispatch, so the footer stays template-bindable rather than hand-pasted per send.

Worked pre-flight checklist

Run this the day you cross the 5,000-messages/day threshold and before any new bulk segment launches:
  1. Domain verifies green. Poll GET /api/v1/email/domains/:domainId/dns-status and confirm overallStatus is valid and no record is warning/invalid — especially spf, dkim, and dmarc.
  2. DMARC policy is at least p=quarantine on the ramp. recordActual on the dmarc row shows the published policy; a still-p=none domain is compliant-but-unprotected today and one regime-escalation away from a gate tomorrow.
  3. Templates carry the unsubscribe footer. The base template includes a footer block with the unsubscribe link (and the postal address for CAN-SPAM) — a template without the footer is a send-gate at the mailbox provider, not an Orbit error you will see locally.
  4. Header pair confirmed on a canary send. Send one message to a seed Gmail address and inspect the raw headers — both List-Unsubscribe and List-Unsubscribe-Post: List-Unsubscribe=One-Click present — before you open the campaign to the segment.
  5. Suppression list is seeded. Bulk-import any legacy opt-out list from your previous ESP (POST /api/v1/email/suppressions/bulk-import) so recipients who already opted out elsewhere do not re-receive and re-complain on the new platform.
  6. Complaint rate baseline is under 0.10%. Poll GET /api/v1/email/suppressions/reputation for a trailing-window baseline, and re-check after the first day of the ramp; pair it with Postmaster Tools as the regime’s authoritative read.
  7. Warm-up before volume. A new domain’s reputation is zero, not good; ramp daily volume per Email → Warm-up posture before bulk traffic, and watch the health tier on the reputation endpoint rather than the send rate.

Localized variants (FR/AR/TR and further locales) are follow-ups: the CAN-SPAM page already has fr/ar/tr mirrors to use as the pattern; this page ships in English first and mirrors next.