emailmarketing.net

List-Unsubscribe and One-Click Unsubscribe (RFC 2369 & RFC 8058)

Exact syntax and semantics of the List-* header fields and the one-click List-Unsubscribe-Post mechanism, including DKIM requirements and why major mailbox providers mandate them.

Operationalesp-operatorsender

Two RFCs define the standard machine-readable unsubscribe mechanism:

  • RFC 2369 (1998) defines the List-* header fields, including List-Unsubscribe.
  • RFC 8058 (2017) adds List-Unsubscribe-Post, turning the HTTPS variant into a one-click action that mail clients can perform on the user's behalf without loading a web page.

Together they are the plumbing behind the "Unsubscribe" link that Gmail, Yahoo, Apple Mail, and Outlook.com render next to the sender name.

RFC 2369: the List-* header fields

RFC 2369 defines six header fields for messages distributed by a mailing list:

Header Purpose Notes
List-Help Full instructions for the list Considered the most important field; acceptable as a standalone implementation
List-Unsubscribe Command/URL to leave the list The field mailbox providers act on
List-Subscribe Command/URL to join the list
List-Post How to post to the list Special value NO for lists that do not accept posting (announcement lists)
List-Owner Contact for the list administrator
List-Archive How to access the list archives

Syntax rules

  • Field contents are angle-bracket-enclosed URLs: <mailto:...> or <http://...>. Internal whitespace inside brackets is ignored; generators must not insert whitespace within brackets, but clients should tolerate poorly formatted entries.
  • Multiple alternate URLs MAY be given as a comma-separated list of angle-bracket-enclosed URLs. Order is preference, left to right — a client uses the leftmost protocol it supports (e.g. HTTPS first, mailto: fallback).
  • Optional comments in parentheses may follow a URL: List-Post: NO (posting not allowed on this list).
  • At most one of each field per message.
  • The fields MUST only be generated by the list/sending system, never by end users.
  • Fields implemented for a list SHOULD appear on all messages distributed by that list.
  • Client parsing rules: if the field content begins with anything other than <, the field SHOULD be ignored; characters after a closing > are ignored unless the next non-whitespace/comment character is a comma; a comma-separated sub-item that is not an angle-bracket URL causes the remainder of the field to be ignored.
  • Sublists redistributing a parent list's mail should replace the parent's List-Help, List-Subscribe, List-Unsubscribe, and List-Owner with their own, preserving List-Archive unless they provide their own.

Examples (from the RFC)

List-Unsubscribe: <mailto:list@host.com?subject=unsubscribe>
List-Unsubscribe: <http://www.host.com/list.cgi?cmd=unsub&lst=list>,
    <mailto:list-request@host.com?subject=unsubscribe>
List-Help: <http://www.host.com/list/>, <mailto:list-info@host.com>
List-Subscribe: <http://www.host.com/list.cgi?cmd=sub&lst=list>,
    <mailto:list-manager@host.com?body=subscribe%20list>
List-Post: <mailto:list@host.com>
List-Owner: <mailto:listmom@host.com>
List-Archive: <http://www.host.com/list/archive/> (Web Archive)

For mailto: URLs, clients are expected to show a confirmation dialog (destination + command) before sending.

RFC 8058: one-click unsubscribe (List-Unsubscribe-Post)

Problem RFC 8058 solves: a plain HTTPS List-Unsubscribe URL cannot safely be fetched automatically — anti-spam scanners, link prefetchers, and security proxies follow GET links, which would unsubscribe users who never asked. RFC 8058 defines a POST-based signal that only a deliberate mail-client action produces.

Header syntax

list-unsubscribe-post = "List-Unsubscribe-Post:" 0*1WSP postarg CRLF
postarg               = "List-Unsubscribe=One-Click"

The header value is exactly List-Unsubscribe=One-Click — nothing else is valid.

Requirements on the sender

Requirement Level
Message carries a List-Unsubscribe header containing one HTTPS URI (other URIs such as mailto: MAY also be present) MUST
The HTTPS URI contains enough information to identify the recipient and the list, so unsubscription completes with no further input MUST
The URI includes an opaque, hard-to-forge component (e.g. HMAC over recipient+list), verified server-side SHOULD
The unsubscribe endpoint completes the action without any further interaction with the user (no login, no confirmation form) MUST
The POST endpoint does not return HTTPS redirects (redirected POSTs are historically unreliable) MUST NOT
Message has at least one valid DKIM signature whose h= tag covers both List-Unsubscribe and List-Unsubscribe-Post MUST

If the required DKIM signature is absent or invalid, the mail receiver SHOULD NOT offer one-click unsubscribe — this is what prevents an attacker from injecting forged unsubscribe headers.

POST semantics (what the mailbox provider sends)

When the user clicks the client's unsubscribe control, the mail receiver performs an HTTPS POST to the URI from List-Unsubscribe, with the key/value pair from List-Unsubscribe-Post as the body:

  • Content-Type: multipart/form-data (SHOULD) or application/x-www-form-urlencoded (MAY).
  • Body: the single pair List-Unsubscribe=One-Click.
  • The request MUST NOT include cookies, HTTP authorization, or any other context information — so the endpoint cannot rely on session state, only on the URI itself.
  • The receiver MUST NOT perform the POST without user consent (i.e. only on an explicit user action, never speculatively).

Examples (from the RFC)

List-Unsubscribe: <https://example.com/unsubscribe/opaquepart>
List-Unsubscribe-Post: List-Unsubscribe=One-Click

POST /unsubscribe/opaquepart HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 26

List-Unsubscribe=One-Click

With a mailto: alternative and multipart/form-data:

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

POST /unsubscribe.html/opaque=123456789 HTTP/1.1
Host: example.com
Content-Type: multipart/form-data; boundary=---FormBoundaryjWmhtjORrn
Content-Length: 124

---FormBoundaryjWmhtjORrn
Content-Disposition: form-data; name="List-Unsubscribe"

One-Click
---FormBoundaryjWmhtjORrn--

Security model

  • Limiting the POST body to one fixed pair prevents the header from being abused to drive arbitrary form submissions.
  • Excluding cookies/authorization prevents linking the unsubscribe to the user's other web activity.
  • As with classic List-Unsubscribe, anyone with a copy of the message can unsubscribe the recipient — the opaque URI component is the mitigation, not a cure.

Why Gmail and Yahoo mandate it

Since February 2024, Gmail and Yahoo require bulk senders (Gmail's threshold: ~5,000+ messages/day to their users) to include RFC 8058 one-click unsubscribe on commercial/promotional mail and to honor unsubscribes within two days. The rationale maps directly to deliverability fundamentals (see Foundations of Email Deliverability):

  • A frictionless unsubscribe is the alternative to the "report spam" button. Every user who unsubscribes instead of complaining protects your complaint rate (Gmail: keep spam-rate below 0.10%, never above 0.30%).
  • The DKIM-coverage requirement ties the unsubscribe promise to an authenticated domain, complementing DMARC alignment.
  • Because the POST carries no cookies or context, honoring it requires sender-side infrastructure that actually maps the opaque token to a real suppression — a proxy for list-hygiene competence.

Sender implementation checklist

  1. Add both headers to every commercial/list message; keep mailto: as a fallback URI alongside the HTTPS one.
  2. Sign with DKIM and include both headers in the signature's h= list.
  3. Make the endpoint idempotent, redirect-free, and instant — suppress on POST, no login, no "are you sure?".
  4. Feed one-click unsubscribes into the same suppression list as complaints from feedback loops; process within 48 hours at the latest.
  5. Keep the in-body unsubscribe link too — the headers complement, not replace, it.
#list-management#list-unsubscribe#one-click#rfc2369#rfc8058#headers#dkim#gmail#yahoo