Since February 2024, Gmail and Yahoo require bulk senders (in Google's terms, roughly anyone sending 5,000 or more messages a day to Gmail accounts) to meet six rules: authenticate with SPF and DKIM, publish DMARC at p=none or stricter, use a From domain that aligns with SPF or DKIM, include one-click unsubscribe (RFC 8058) in marketing mail, and keep spam complaints under 0.3%, ideally under 0.1%. Google's own summary is in its sender guidelines at https://support.google.com/a/answer/81126.

Below is each requirement, how to meet it, and how to check it. We use example.com throughout. Even if you send far fewer than 5,000 a day, meeting these is the cheapest deliverability work you can do.

The requirements at a glance

Requirement What it means in practice Guide
SPF Your sending IPs are listed in the envelope sender domain's SPF record How to set up an SPF record
DKIM Every message is signed, ideally with your own domain How to set up DKIM
DMARC A record at _dmarc.example.com, at least p=none How to set up DMARC
Aligned From The From domain matches the SPF or DKIM domain Below
One-click unsubscribe List-Unsubscribe + List-Unsubscribe-Post headers in marketing mail Below
Complaint rate Under 0.3% reported as spam; aim for under 0.1% Below

Does this apply to you?

The threshold is about volume to Gmail addresses from your domain, across all your mail: newsletters, receipts, notifications, everything. If you are near it, assume it applies. Yahoo announced matching requirements at the same time.

Two practical points:

  • Count all your senders together. Your app's provider, your newsletter tool and your own server all send as example.com.
  • Growth counts. A product launch or a re-engagement campaign can push you over the line for a few days. Being compliant all the time is simpler than tracking it.

Requirement 1 and 2: SPF and DKIM

Check what is published:

dig +short TXT example.com
dig +short TXT mail._domainkey.example.com

Replace mail with the selector your provider uses; you can find it in the s= tag of a message's DKIM-Signature header.

The common gap is a provider that signs DKIM with its domain rather than yours. That passes DKIM but does nothing for alignment. Finish the provider's domain authentication so signatures carry d=example.com.

If you run your own server, OpenDKIM handles signing; our self-hosted email server guide has the configuration we use.

Requirement 3: DMARC at p=none or stricter

dig +short TXT _dmarc.example.com

Minimum compliant record:

v=DMARC1; p=none; rua=mailto:dmarc@example.com

The rua tag is not part of the requirement, but without it you are publishing a policy blind. The reports show every IP sending as your domain, which is how you find the sender you forgot. When the reports are clean, plan the move to enforcement with our DMARC p=none to p=reject guide.

Requirement 4: An aligned From domain

DMARC passes only if SPF or DKIM passes for the same domain as the From header (or the same organizational domain, under the default relaxed alignment). Check a real message: in Gmail, open it, choose "Show original" and compare:

From: Example Shop <news@example.com>
Authentication-Results: mx.google.com;
       dkim=pass header.i=@example.com;
       spf=pass smtp.mailfrom=bounces.example.com;
       dmarc=pass (p=NONE) header.from=example.com

Here DKIM aligns exactly and SPF aligns in relaxed mode, so DMARC passes. If header.i showed the provider's domain and smtp.mailfrom showed the provider's bounce domain, DMARC would fail even though both checks "pass".

Never send bulk mail with a From address at gmail.com or yahoo.com through a third-party service or your own server. You cannot align with a domain you do not control, and yahoo.com publishes p=reject, so such mail fails DMARC. Send from your own domain.

Requirement 5: One-click unsubscribe (RFC 8058)

Marketing and promotional mail needs two headers:

List-Unsubscribe: <https://example.com/unsubscribe?u=abc123>, <mailto:unsubscribe@example.com?subject=unsubscribe>
List-Unsubscribe-Post: List-Unsubscribe=One-Click

RFC 8058 says:

  • List-Unsubscribe must contain an HTTPS URL. The mailto: is an optional extra.
  • List-Unsubscribe-Post must be exactly List-Unsubscribe=One-Click.
  • The mailbox provider unsubscribes the user by sending an HTTP POST to the URL with the body List-Unsubscribe=One-Click. Your endpoint must act on that POST without a login, confirmation page or further clicks.
  • Both headers must be covered by a valid DKIM signature.

Most newsletter platforms add these automatically. If you send from your own code, add the headers per recipient, with a token in the URL that identifies the subscriber. On our own server, OpenDKIM signs both headers through its SignHeaders setting in /etc/opendkim.conf:

SignHeaders  From,To,Subject,Date,Message-ID,MIME-Version,Content-Type,List-Unsubscribe,List-Unsubscribe-Post

If you build the endpoint yourself, the POST handler can be very small. A Flask example, where unsubscribe_by_token is your own function that marks the subscriber as opted out:

from flask import Flask, request

app = Flask(__name__)

@app.post("/unsubscribe")
def one_click_unsubscribe():
    token = request.args.get("u", "")
    if request.form.get("List-Unsubscribe") == "One-Click":
        unsubscribe_by_token(token)
    return "", 200

Handle GET on the same URL separately, with a page that confirms the unsubscribe for people who click the link in a browser. Do not make the POST depend on cookies or a session; the request comes from the mailbox provider, not the subscriber's browser.

Test your endpoint the way Gmail will call it:

curl -i -X POST \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data 'List-Unsubscribe=One-Click' \
  'https://example.com/unsubscribe?u=abc123'

You want a 200 response, and the subscriber should be marked unsubscribed in your database. Keep a visible unsubscribe link in the message body too; it is what most people actually click.

Transactional messages such as password resets and receipts do not need these headers.

Requirement 6: Spam complaints under 0.3%

The complaint rate is the share of your delivered mail that recipients mark as spam. Gmail requires it to stay below 0.3%; aim for below 0.1% so a single bad campaign does not push you over.

Measure it in Google Postmaster Tools: add your domain, verify it with a TXT record, and check the spam rate graph once you have enough Gmail volume.

How to keep it low:

  • Only mail people who asked for it, and say clearly at signup what they will get.
  • Make unsubscribing easier than reporting spam (see requirement 5).
  • Stop mailing people who have not opened in months.
  • Use a recognizable From name and a subject that matches the content.
  • Ramp up gradually after any pause or on a new domain or IP; see IP warm-up.

Self-hosted or hosted: who does what

The requirements are the same either way, but the work lands in different places.

Task Hosted provider Your own server
SPF Add the provider's include, or a custom return-path subdomain ip4: for your server's IP
DKIM Complete the provider's domain authentication OpenDKIM with your own key and selector
DMARC You publish it You publish it
Unsubscribe headers Usually automatic in marketing tools Your code adds them; OpenDKIM signs them
Complaint rate Provider dashboards plus Postmaster Tools Postmaster Tools and your own bounce handling

With a provider, the usual job is finishing domain authentication properly. On your own server you control everything, which also means nothing happens unless you set it up. If you are weighing the two, is self-hosting email worth it is an honest comparison.

A 15-minute compliance check

  1. Run the three dig commands in the verification section below and confirm one SPF, one DKIM and one DMARC record.
  2. Send a marketing message to a Gmail account and open "Show original".
  3. Confirm SPF, DKIM and DMARC all say PASS, and header.from matches the DKIM header.i domain.
  4. Confirm the raw message has both List-Unsubscribe headers, and that they appear in the DKIM h= list.
  5. POST to the unsubscribe URL with curl and confirm the subscriber is opted out.
  6. Open Google Postmaster Tools and check the spam rate is under 0.1%.

If any step fails, fix that one before anything else.

Common mistakes

  • DKIM signed with the provider's domain. It passes DKIM and fails alignment. Check the d= value, not just the word pass.
  • A second SPF record for a new tool. Two records means permerror. Merge them.
  • Unsubscribe endpoint that only works with GET. One-click requires POST handling, without a confirmation page.
  • Unsigned List-Unsubscribe headers. RFC 8058 requires them to be covered by DKIM.
  • Treating 0.3% as the goal. It is the limit. Aim for under 0.1%.
  • Forgetting smaller senders on the same domain. Your helpdesk or CRM counts toward volume and needs authentication too.

How to verify it worked

DNS first:

dig +short TXT example.com
dig +short TXT mail._domainkey.example.com
dig +short TXT _dmarc.example.com

Then send a real marketing message to port25's verifier (check-auth@verifier.port25.com), to mail-tester.com and to a Gmail account. From your own server you can use swaks:

swaks --to check-auth@verifier.port25.com --from news@example.com \
  --server mail.example.com --port 587 --tls \
  --auth LOGIN --auth-user news@example.com \
  --header 'List-Unsubscribe: <https://example.com/unsubscribe?u=test>' \
  --header 'List-Unsubscribe-Post: List-Unsubscribe=One-Click'

In Gmail's "Show original", confirm SPF, DKIM and DMARC all pass and header.from matches your domain. Check that the h= list in the DKIM-Signature header includes List-Unsubscribe and List-Unsubscribe-Post. Gmail may show an "Unsubscribe" link next to the sender name once it trusts the headers. Our email checker checks the DNS side for any domain.

If you want an audit of all six requirements across every service that sends as your domain, with fixes applied, that is our Deliverability Fix; details are on the pricing page.