Deliverability

What is one-click unsubscribe, and how do I implement List-Unsubscribe?

One-click unsubscribe is the mechanism behind the Unsubscribe control your mail client draws next to the sender name, distinct from any link inside the message. It is specified in RFC 8058, and Gmail and Yahoo both require it from bulk senders on marketing mail.

What problem was it invented to solve?

That a plain unsubscribe URL cannot tell a person from a robot.

An older mechanism already allowed an HTTPS link in a List-Unsubscribe header. It was unusable on its own, and the specification explains why:

But anti-spam software often fetches all resources in mail header fields automatically, without any action by the user, and there is no mechanical way for a sender to tell whether a request was made automatically by anti-spam software or manually requested by a user.

Senders responded by putting a confirmation page behind the link, which defeated the purpose: a mail client could no longer unsubscribe on the reader's behalf without a human clicking through. One-click adds a POST that only a receiver acting on a real user's instruction will send, so the sender can act on it immediately.

The motivation is worth keeping in view, because it explains why providers care. The specification is candid that the alternative to an easy unsubscribe is a complaint: "if an unsubscription process is too difficult, the recipient's alternative is to report mail from the sender as junk until the mail no longer appears in the recipient's inbox."

What do I have to put in the message?

Two headers, both signed.

The sender's obligations are short and all mandatory:

A mail sender that wishes to enable one-click unsubscriptions places one List-Unsubscribe header field and one List-Unsubscribe-Post header field in the message. The List-Unsubscribe header field MUST contain one HTTPS URI. It MAY contain other non-HTTP/S URIs such as MAILTO:. The List-Unsubscribe-Post header MUST contain the single key/value pair "List-Unsubscribe=One-Click".

Google's documentation shows the same pair concretely, as:

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

The signature requirement is the one that silently removes the button:

The List-Unsubscribe and List-Unsubscribe-Post headers MUST be covered by the signature and included in the "h=" tag of a valid DKIM-Signature header field.

If the message does not have the required DKIM signature, the mail receiver SHOULD NOT offer a one-click unsubscribe for that message.

So a message with both headers, sent from a domain that does not DKIM-sign or whose signature does not list those headers, has done all the work and gets nothing. Nothing errors. The control just never appears.

What must my endpoint do?

Accept an anonymous POST, act on it, and answer without redirecting.

The URI carries everything, because the POST body is fixed:

The URI in the List-Unsubscribe header MUST contain enough information to identify the mail recipient and the list from which the recipient is to be removed, so that the unsubscription process can complete automatically.

Three constraints then follow, and each rules out a common design.

  • No context of any kind. "The POST request MUST NOT include cookies, HTTP authorization, or any other context information." An endpoint that requires a session is not implementable.
  • No redirect. "The mail sender MUST NOT return an HTTPS redirect, since redirected POST actions have historically not worked reliably, and many browsers have turned redirected HTTP POSTs into GETs." A canonical-host redirect or a trailing-slash rewrite will break this.
  • A hard-to-forge component. The URI "SHOULD include an opaque identifier or another hard-to-forge component", because otherwise anyone can unsubscribe anyone by guessing addresses, or by sending spam that points at your unsubscribe endpoint.

There is a fourth requirement that is not in the RFC but is enforced anyway. Google's compliance dashboard holds you responsible for processing the request even when something in front of your server ate it:

This means that if services like Cloudflare block these requests and keep them from your servers, you’re still responsible if the request isn't processed.

A bot-protection rule that challenges an unauthenticated POST from an unfamiliar client is exactly the shape of rule that will do this.

No. Google requires both on marketing mail:

Marketing messages and subscribed messages must support one-click unsubscribe, and include a clearly visible unsubscribe link in the message body.

The in-body link is also what most consumer protection law requires, which the header alone does not satisfy. Treat them as two obligations that happen to serve the same reader.

How long do I have to honour it?

Two days at Google, and its dashboard checks this separately from whether the header exists. An entry flagged "Needs work" against honour-unsubscribe means "You might receive this entry if you don't honor the unsubscribe requests within 48 hours."

The legal deadlines are different again and generally longer, so the provider requirement is the binding one in practice.

What does Bird do here?

All of it, on marketing sends.

Bird puts both headers on every marketing message, signs them, hosts the endpoint, and records the opt-out so the next campaign skips the address. Because the platform owns that header pair, setting your own List-Unsubscribe on a marketing send is rejected rather than silently overridden. The unsubscribe links guide has the detail, including how to place the in-body link yourself rather than take the default footer, and categories explains why transactional mail gets neither.

Bangun di jaringan yang sama.

Kunci API uji coba langsung tersedia untuk Anda. Akses produksi terbuka saat Anda menambahkan metode pembayaran dan memverifikasi pengirim.

Mulai dengan satu channel.
Tambahkan yang lain saat Anda siap.

API key uji coba langsung tersedia untuk Anda. Akses produksi terbuka setelah Anda menambahkan metode pembayaran dan memverifikasi pengirim.

Menggunakan Claude Code, Cursor, atau Codex? Salin prompt pengaturan dan agen Anda akan menginstal Bird CLI dan skill untuk Anda. Pilih milik Anda:

Cursor