GuidesPublished 8 min read
List-Unsubscribe Header: How One-Click Unsubscribe Works
The List-Unsubscribe header is an email header that tells mail apps how to unsubscribe the reader, so Gmail, Yahoo and others can show their own Unsubscribe button next to your name. For one-click unsubscribe (RFC 8058) you add two headers: List-Unsubscribe with an HTTPS link, and List-Unsubscribe-Post: List-Unsubscribe=One-Click. When the reader clicks the button, the mail provider sends a POST request to that link, and your server unsubscribes them on the spot, with no page and no confirmation.
List-Unsubscribe: <https://links.example.com/u/7Hq2mXc>, <mailto:unsubscribe@example.com?subject=unsubscribe>
List-Unsubscribe-Post: List-Unsubscribe=One-Click
Below: what each part means, the endpoint you need behind the link, the DKIM detail that quietly breaks it, what Gmail and Yahoo ask for, and how to test it.
What is the List-Unsubscribe header?
It's a header defined in 1998 by RFC 2369 that lists one or more ways to unsubscribe, each in angle brackets: an HTTPS link, a mailto: address, or both. Mail apps read it and offer an Unsubscribe button in their own interface, so the reader never has to find a link at the bottom of your email.
On its own, though, the old header was awkward. A mailto: link sends an email the reader has to send, and an HTTPS link opens a web page they have to deal with. RFC 8058, published in 2017, added the second header that makes it one click.
What is one-click unsubscribe (RFC 8058)?
RFC 8058 adds the List-Unsubscribe-Post header. When it's present, the mail provider doesn't open your link in a browser: it sends an HTTP POST to it from its own servers, with the body List-Unsubscribe=One-Click. Your server takes that request as the unsubscribe itself.
The RFC's rules, in short:
| Rule | What it means |
|---|---|
List-Unsubscribe must contain one HTTPS URI | A mailto: can sit next to it, but the HTTPS link is required for one-click |
List-Unsubscribe-Post must be exactly List-Unsubscribe=One-Click | No other value, no extra parameters |
| Both headers must be covered by a valid DKIM signature | They must be listed in the signature's h= tag |
| The POST carries no cookies, HTTP auth or other context | The link itself has to identify who is unsubscribing |
The last rule is why the URL needs an opaque token: something like /u/7Hq2mXc that your server can map back to one recipient and one list. Don't put the email address in the URL in plain text, and sign or randomise the token so nobody can unsubscribe other people by guessing.
Do Gmail and Yahoo require the List-Unsubscribe header?
For bulk senders, yes. Gmail asks anyone who sends more than 5,000 messages a day to personal Gmail accounts to support one-click unsubscribe in marketing and subscribed messages, using exactly these two headers, to include a clearly visible unsubscribe link in the body as well, and to honour unsubscribes within 2 days. Yahoo asks bulk senders for a working List-Unsubscribe header that supports one-click for marketing and subscribed messages, calls the POST method (RFC 8058) highly recommended while still accepting mailto:, and also wants a visible link in the body and unsubscribes honoured within 2 days.
Both write these rules for marketing and subscribed mail, not for one-to-one B2B email. We'd add the header to cold email anyway, for two reasons:
- It turns complaints into unsubscribes. Someone who doesn't want your email will either unsubscribe or click "Report spam". A button right next to your name makes the first one easier, and spam complaints are what hurt a sending domain (Gmail asks for a rate under 0.3%).
- It's free. Two headers and one endpoint. Gmail, not you, decides whether and when to show its button, but it can't show one without the header.
How do you add the List-Unsubscribe header?
It depends on how you send:
- Through an email service or cold email tool: look for a setting called one-click unsubscribe or List-Unsubscribe. Most add both headers for you; check that the link points at a domain you own.
- From your own code: add the two headers when you build the message, before DKIM signing. In Node.js with Nodemailer, for example:
const unsubscribe = [
`<https://links.example.com/u/${token}>`,
"<mailto:ana@example.com?subject=unsubscribe>",
].join(", ");
await transporter.sendMail({
from: "Ana <ana@example.com>",
to: lead.email,
subject: "Quick question",
text: body,
headers: {
"List-Unsubscribe": unsubscribe,
"List-Unsubscribe-Post": "List-Unsubscribe=One-Click",
},
});
- From Gmail or Outlook by hand: you can't. Neither lets you set custom headers from the app, which is one reason cold email goes through a sending tool.
What should the unsubscribe endpoint do?
Two things, depending on the method:
- POST: unsubscribe the recipient the token points to and answer with
200. No redirect, no login, no confirmation step. The request comes from Gmail's or Yahoo's servers, not from the reader's browser. - GET: show a page with a single Unsubscribe button that sends a POST. Never unsubscribe on a GET.
The GET rule isn't in the RFC, but it matters in practice. Corporate mail filters and link scanners open the links in incoming email to check them, and as the RFC itself notes, anti-spam software often fetches the resources in mail headers automatically. If a GET unsubscribed, those scanners would unsubscribe people who never clicked anything.
A minimal handler, as a Next.js route:
// app/u/[token]/route.ts
export async function POST(_req: Request, { params }: { params: Promise<{ token: string }> }) {
const recipient = await recipientForToken((await params).token);
if (recipient) await unsubscribe(recipient); // suppress the address everywhere, stop every sequence
return new Response("You're unsubscribed.", { status: 200 });
}
export async function GET() {
return new Response(
`<form method="post"><p>Stop receiving these emails?</p><button>Unsubscribe</button></form>`,
{ headers: { "content-type": "text/html" } },
);
}
Make the POST idempotent: the same request can arrive more than once, and a second one for someone already unsubscribed should still return 200.
Why isn't the Gmail Unsubscribe button showing?
Check these in order:
- Both headers are there. Open the email in Gmail, choose "Show original" and search for
List-Unsubscribe. You need both lines, spelled exactly as above. - The link is HTTPS. A
mailto:alone doesn't give you one-click. - DKIM passes and covers both headers. In "Show original", DKIM should say PASS. A tool that adds the headers after the message is signed, or a gateway that rewrites them, breaks the signature for those headers. Our DKIM checker shows whether your domain publishes a key at all.
- It's still Gmail's call. Gmail shows its button based on the sender as well as the headers; a new sender with little history may not see it at first, even with everything right. Outlook.com makes its own decision too.
You can also test the endpoint yourself, the way Gmail would call it:
curl -i -X POST "https://links.example.com/u/7Hq2mXc" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data "List-Unsubscribe=One-Click"
You should get 200, and the recipient should be unsubscribed.
Do you still need an unsubscribe link in the email body?
Gmail and Yahoo ask bulk senders for both: the header for their button, and a clearly visible link in the body. The body link can lead to the same GET page. For cold email, a plain line works as well, such as "Not interested? Reply 'stop' and I won't email you again", as long as you read the replies and act on them.
Where should the unsubscribe link point?
At a domain you own and send from, or a subdomain of it, such as links.yourdomain.com. A link to your email tool's shared domain puts you next to every other customer of that tool, and it's a domain the reader has never heard of in an email that claims to be from you.
When this guide isn't enough
The header makes unsubscribing easy. It doesn't make unwanted email wanted: if people unsubscribe or complain in large numbers, the problem is the list or the message, and no header fixes that. Fix who you're emailing first.
How Ballast handles it
Every email Ballast sends carries both headers, with an HTTPS link plus a mailto: to the sending mailbox, added when the message is built, before your mail provider signs it with DKIM. The link sits on your own link domain (links.yourdomain.com, one CNAME record), the GET opens a neutral page with your name on it and an Unsubscribe button, and the one-click POST unsubscribes immediately: the address is suppressed and every sequence it's in stops. You choose per workspace whether the body carries a link or a "reply stop" line, and "stop" replies are read and acted on either way. The docs on sending safety cover the rest.
FAQ
What is the List-Unsubscribe header?
An email header (RFC 2369) that tells mail apps how to unsubscribe the reader, with an HTTPS link, a mailto address or both. Gmail and Yahoo use it to show their own Unsubscribe button.
What is List-Unsubscribe-Post?
The header from RFC 8058 that turns the link into one-click unsubscribe. Its value must be exactly List-Unsubscribe=One-Click; the mail provider then sends a POST to your link and you unsubscribe the reader without a confirmation step.
Is a mailto List-Unsubscribe enough for Gmail?
Not for one-click. RFC 8058 requires an HTTPS link in the header, and Gmail's setup uses the HTTPS link with List-Unsubscribe-Post. Keep a mailto next to it for older mail apps.
Does the List-Unsubscribe header need DKIM?
Yes. RFC 8058 says both headers must be covered by a valid DKIM signature, listed in its h= tag. Add them before the message is signed.
How fast do I have to process an unsubscribe?
Gmail and Yahoo both ask bulk senders to honour unsubscribes within 2 days. With one-click, there's no reason to wait: unsubscribe on the POST.
Sources
- RFC 8058: Signaling One-Click Functionality for List Email Headers, checked 20 October 2026.
- RFC 2369: The Use of URLs as Meta-Syntax for Core Mail List Commands.
- Gmail email sender guidelines and FAQ, checked 20 October 2026.
- Yahoo sender best practices, checked 20 October 2026.