LetterDuck
Deliverability

The List-Unsubscribe header: RFC 8058 in practice

Two headers, one POST request, and a rule most senders get backwards: making unsubscribing easy is how you protect your deliverability.

Every campaign our system sends carries these two headers. This is the literal output of our send path, with only the per-recipient token shortened:

List-Unsubscribe: <https://nostalgiapost.com/api/unsubscribe?token=9f2c...>, <mailto:unsubscribe@nostalgiapost.com?subject=unsubscribe>
List-Unsubscribe-Post: List-Unsubscribe=One-Click

That pair is what "one-click unsubscribe" means technically, it is what RFC 8058 specifies, and it is what Gmail and Yahoo require from bulk senders sending commercial mail. Google's requirement took effect February 1, 2024, with June 1, 2024 as the deadline for senders who already carried some unsubscribe link; Yahoo said only that enforcement would begin in June 2024. It is also one of the cheapest deliverability wins available, because the alternative exit from your list is the spam button, and the spam button is the one that hurts. The wider context lives in our email deliverability handbook; this article is just these two headers, done properly.

What RFC 8058 actually requires

RFC 8058 (published January 2017) exists because of a quiet failure mode in the older mailto-only approach: mail software sometimes prefetches URLs found in headers, and a GET request that unsubscribes someone means people get silently removed from lists they wanted. The fix is to require deliberate semantics. Three rules do the work:

  1. The List-Unsubscribe header must contain at least one HTTPS URI. A mailto alone does not qualify for one-click.
  2. The List-Unsubscribe-Post header must contain exactly List-Unsubscribe=One-Click. This is the signal that the URL accepts the one-click flow.
  3. When the user clicks unsubscribe in their mail client, the client sends an HTTP POST to your URL with the body List-Unsubscribe=One-Click. Your server must complete the unsubscribe on that POST, without any further interaction: no confirmation page that requires a click, no login wall, no survey first.

There is a fourth requirement that trips up home-rolled implementations: the message's DKIM signature must cover both headers. If your relay signs the message before your code adds the headers, they are outside the signature and the one-click flow is not compliant. Any competent ESP handles this ordering for you, but if you built your own pipeline, check it.

The URL itself should carry a per-recipient token, as ours does. The POST arrives with no cookie and no authenticated user, so the token is the only thing telling you who is unsubscribing. Make it unguessable, and make it work forever; a token that expires after 30 days breaks unsubscribes from old emails, which is exactly when frustrated people go looking for the spam button.

Why both URL and mailto

The HTTPS URI satisfies RFC 8058 and powers the one-click button in Gmail and Yahoo. The mailto is a fallback for clients that predate the standard or implement only the older RFC 2369 behavior: they generate an email to your unsubscribe address instead. If you include the mailto, something on your side has to actually read that mailbox and process the requests, which is why our mailto points at a real routed address and not a decoy.

Belt and suspenders, and each strap costs one header. Gmail's own bulk-sender documentation asks for one-click support; the mailto costs nothing extra and catches the stragglers. The full requirement list, including the authentication rules that come with it, is in our walkthrough of Gmail's bulk sender requirements.

The 2-day rule, and why we ignore the allowance

Google's sender guidelines require unsubscribe requests to be honored within 2 days. That is the compliance ceiling, not a design target. We process the unsubscribe the moment the POST arrives: the recipient goes onto the entity's suppression list in the same request, and that list is checked before every future send.

The reasoning is not virtue. It is that delayed unsubscribes generate complaints. A person who unsubscribed on Tuesday and receives your Thursday campaign does not think "the 48-hour window has not elapsed." They think it did not work, and they report you as spam, and now the exit you gave them for free has been converted into the expensive kind. Batch-processing unsubscribes nightly was defensible engineering in 2010. In a world where the suppression check is one indexed query, holding a fresh unsubscribe in a queue for two days buys you nothing and risks the complaint you built all of this to avoid.

The math on hiding your unsubscribe

Some senders still shrink the unsubscribe link, bury it under a login, or leave the headers off so Gmail shows no unsubscribe affordance. The theory is retention. The arithmetic says otherwise.

Gmail's complaint threshold structure gives you a target spam rate under 0.1% and a critical limit of 0.3%. At 0.1%, your budget is one complaint per 1,000 delivered emails. One. A subscriber who wants out and finds no obvious exit does not stay and read your newsletter; they click "report spam," which is always one click and never hidden. So the real trade on every tired subscriber is: an unsubscribe, which costs you a recipient who had stopped converting anyway, or a complaint, which spends your entire allowance for a thousand deliveries. Cross 0.3% and Gmail withholds delivery mitigation until you have held under the line for 7 consecutive days, degrading placement for everyone on your list, including the people who love your mail.

An unsubscribe is free. A complaint is a thousandth of your budget. Price your UX decisions accordingly, and while you are at it, stop sending to people who have gone quiet: a double opt-in at the front door and a sunset policy at the back keep the tired cohort small in the first place.

Testing yours in five minutes

Send a real campaign message to a Gmail address you control, then open it and click the three-dot menu, then "Show original." Search the raw text for List-Unsubscribe. You are checking three things: both headers are present, the List-Unsubscribe value contains an HTTPS URL (not only a mailto), and the DKIM verdict at the top of the page says PASS.

Then check the rendered message for Gmail's own unsubscribe affordance next to the sender name, and click it. Confirm the address actually lands in your suppression store, and confirm a second send skips it. When we wired this up, the end-to-end test (click, POST handled, suppression row written, next send suppressed) was the test that mattered; the headers merely being present proves formatting, not behavior.

Two headers, a POST handler, and an immediate suppression write. Ship that, and the only people leaving your list will be the ones who were already gone.