/ TL;DR
One-click unsubscribe is two headers plus a DKIM signature that covers them. You add List-Unsubscribe with an HTTPS URL and List-Unsubscribe-Post with the exact value List-Unsubscribe=One-Click, and your DKIM signature must include both header names in its h= tag. Then the mailbox provider renders its own unsubscribe control.
When a recipient clicks it, the provider sends an HTTP POST to your URL with the body List-Unsubscribe=One-Click. Your endpoint must process that POST with no login, no confirmation page, and no redirect, then return a 2xx status. POST — not GET — because link scanners were triggering GET URLs and unsubscribing people who never clicked.
It's required for bulk senders — 5,000+ messages a day — at Gmail and Yahoo since 2024 and Microsoft since 2025, for marketing mail. The most common failure is DKIM not covering both headers, which silently hides the button. Keep your footer link too; one-click is an added layer, not a replacement.
/ 01
What one-click actually is
The first thing to correct is a common misunderstanding: one-click unsubscribe is not a button you put in your email template. You don't design it or place it. Instead, you add specific headers to the message, and the mailbox provider — Gmail, Yahoo, Apple Mail — reads those headers and renders its own unsubscribe control in its interface, typically right next to your sender name. Your job is to supply a valid, signed signal that the provider can trust; the provider decides how and where to display the control.
This matters because it's now mandatory for bulk senders. Gmail and Yahoo have required one-click unsubscribe since early 2024, and Microsoft joined the enforcement in May 2025, with non-compliant bulk mail routed to Junk or rejected outright with a 550 error. The threshold everyone references is 5,000 or more messages per day to a given provider's users, and the requirement applies to marketing and promotional mail — transactional messages like receipts and password resets are exempt, since they carry nothing to unsubscribe from.
The reason to treat this as a priority rather than a checkbox is that it's one of the highest-return deliverability moves available. A frictionless unsubscribe is the direct alternative to the Report Spam button: give people an easy exit and they take it quietly; make it hard and they complain, which does far more damage to your reputation. Implemented correctly, one-click both satisfies the mandate and actively lowers your complaint rate. Our bulk sender rules guide covers where this sits among the other requirements; this guide is the implementation.
/ 02
The two headers
One-click is signaled by two headers that must appear together on the same message. The first is List-Unsubscribe, which carries the unsubscribe destinations. It must contain at least one HTTPS URL, and it may also include a mailto: address as a fallback for clients that don't support one-click. A complete example:
List-Unsubscribe-Post: List-Unsubscribe=One-Click
The second header, List-Unsubscribe-Post, is what signals that your endpoint actually supports the automated one-click flow rather than merely offering a link that might need extra steps. Its value has to be exactly List-Unsubscribe=One-Click — no variations, no extra parameters, no creative formatting. Providers check for this precise string before offering their native button, and a typo here means no button.
One design constraint shapes the HTTPS URL: the one-click POST carries no extra arguments, so the URL itself must contain everything needed to identify both the recipient and the specific list they're leaving. That's done with an opaque token embedded in the path or query — something hard to guess that maps, on your side, to a subscriber and a list, without exposing an email address or other personal data in the link. Every recipient gets a unique URL.
/ 03
The DKIM requirement
This is the requirement that catches the most people, so it gets its own section. The message must carry a valid DKIM signature, and that signature must cover both unsubscribe headers — meaning both List-Unsubscribe and List-Unsubscribe-Post have to be listed in the signature's h= tag. If they aren't in the signed set, the provider treats the one-click signal as unverified and won't show the button, no matter how correct the headers themselves look.
The reason is security. Signing the unsubscribe headers stops anyone in the delivery chain from injecting or rewriting your unsubscribe URL in transit — without it, a malicious relay could swap the destination and unsubscribe your recipients, or worse. Because the button is an action taken on the recipient's behalf, the provider insists on cryptographic proof that the sender really set those headers, and DKIM is the mechanism.
In practice this trips up senders whose signing happens in the wrong place or through a library that doesn't reliably add custom headers to the signature — a well-known rough edge with some built-in signing implementations, where the header is present in the message but absent from h=. The fix connects to a principle from DKIM troubleshooting generally: sign the finished message, with the unsubscribe headers already in place, and confirm they made it into the signed set. Our DKIM signature guide covers signing order, and the DKIM checker confirms your record resolves.
/ 04
POST, not GET
When a recipient clicks the provider's unsubscribe control, the provider sends an HTTP POST request to the HTTPS URL from your List-Unsubscribe header. The request body is exactly List-Unsubscribe=One-Click, sent as ordinary form data. There's no browser, no page load, no redirect — just a POST hitting your endpoint, which processes the opt-out and returns success. The user sees a small confirmation from their mail client, and they're done.
The choice of POST over GET is the entire reason RFC 8058 exists, and it's worth understanding rather than just obeying. The older List-Unsubscribe mechanism used plain URLs that clients and security tools would sometimes fetch with a GET — link scanners, preview generators, and anti-phishing crawlers routinely open URLs in headers to check them. When those URLs were GET-based unsubscribe links, the scanners unsubscribed people who had never clicked anything, silently shrinking lists through automated prefetching.
Requiring a POST with a specific body solves that, because scanners and prefetchers issue GETs, not POSTs carrying List-Unsubscribe=One-Click. Only a deliberate, provider-initiated action produces the exact request that triggers the opt-out. The direct consequence for your build is a hard rule: your endpoint must act on POST and must never unsubscribe anyone on a GET. A GET to that URL should do nothing that changes state.
/ 05
Building the endpoint
The endpoint itself is simple, and simplicity is the point — most failures come from adding things that shouldn't be there. The core logic is short: accept the POST, confirm the body is the expected one-click value, look up the token, suppress that recipient from that list, and return a 2xx status. In outline:
if method != POST → 405
if body != "List-Unsubscribe=One-Click" → 400
recipient, list = resolve(token)
suppress(recipient, list) # idempotent
return 200
Around that core, a set of hard constraints separates a working endpoint from one the provider will distrust. It must require no login, cookie, captcha, or confirmation page — the POST arrives with none of those, so anything you demand breaks the flow. It must not redirect; returning a 301 or 302 to a preference page fails the request, and bouncing a POST to a GET loses the body. It must return a 2xx: a 403, 500, or redirect makes the unsubscribe fail, and a recipient who sees it fail reaches for Report Spam instead.
Two more constraints are easy to miss. The endpoint must be idempotent — providers may retry, so a second POST for the same token should return success without erroring or, worse, toggling the person back on. And your tokens must be long-lived: recipients unsubscribe from messages weeks or months after delivery, so a short-lived signed URL that expires in the interim will fail exactly when someone finally acts. Use durable, opaque tokens that stay valid, and process the suppression synchronously so it takes effect immediately rather than waiting on a batch job.
/ 06
One-click, footer, and preference center
These three are often confused, and conflating them causes both compliance and retention mistakes. They're distinct layers with distinct jobs, and a healthy program runs all three. The header one-click is the inbox-level exit the provider renders — instant, frictionless, and mandated for bulk senders. It must remove the recipient immediately, with nothing in the way.
The footer link in your email body is the in-message exit, and it stays necessary for two reasons: not every mail client surfaces the header button, and a visible unsubscribe link is a legal requirement under anti-spam laws like CAN-SPAM. Removing it because you added one-click is a mistake on both counts. The header button and the footer link coexist; they're not alternatives.
The preference center is the retention tool, and it's where senders most often go wrong. It's a page where someone can choose fewer emails or different topics instead of leaving entirely — genuinely valuable, because some people want less mail, not none. But it can never be what the one-click POST lands on: gating the header unsubscribe behind a preference selection violates the standard and gets the button distrusted. Offer the preference center as its own separate link in the body, so it's an option for those who seek it, while one-click stays an instant, unconditional opt-out.
/ 07
Testing what's delivered
The cardinal rule of verifying one-click is to test the delivered message, not the template. A template preview tells you almost nothing, because the headers and DKIM signature are added and modified along the sending path — the message a recipient receives is the only source of truth. Send a real message through your actual production path, to a real mailbox, and inspect the raw headers of what arrives.
In that delivered message, confirm four things. Both List-Unsubscribe and List-Unsubscribe-Post are present. The List-Unsubscribe URL is HTTPS. The List-Unsubscribe-Post value is exactly right. And the DKIM signature's h= tag lists both header names. Our email header analyzer breaks these apart, and the bulk sender compliance checker validates one-click alongside the rest of the Gmail, Yahoo, and Microsoft requirements in one pass.
Then test the endpoint directly: issue a POST with the one-click body and confirm it returns a 2xx and actually suppresses the recipient, and issue a GET to confirm it changes nothing. Watch for a delivery chain that rewrites headers after signing, which quietly breaks DKIM coverage and hides the button — a staging template with a different signing path proves less than you'd think. Verifying the real path, end to end, is the difference between believing you're compliant and being compliant. Keeping that true across every stream as your sending evolves is the standing operation we run.
/ 08 — FAQ