October 2026 Workspaces: invite your team

One-click unsubscribe (RFC 8058)

Gmail and Yahoo require it for bulk senders now. A syntactically valid unsubscribe link can still fail compliance.

The problem

Since February 2024, Gmail requires bulk senders to support one-click unsubscribe. Google's own threshold is explicit: senders of more than 5,000 messages a day to Gmail addresses, counted per top-level domain including subdomains. Miss it and mail can be deferred, spam-foldered, or rejected outright.

Yahoo followed in June 2024 with the same requirement, but with one real difference worth knowing: Yahoo has explicitly declined to publish a volume threshold. Its own FAQ states "we will not specify a volume threshold." A Yahoo product lead has said publicly it isn't 5,000, or 6,000, or 4,000. Treating "Gmail and Yahoo both use 5,000/day" as one unified rule, a claim repeated often, is not accurate.

Both carve out transactional mail. Password resets, receipts, and other one-to-one operational messages aren't in scope, only bulk marketing and promotional sends.

How RFC 8058 actually works

RFC 8058 adds one header to the older List-Unsubscribe mechanism (RFC 2369, 1998): List-Unsubscribe-Post. Together they signal that unsubscribing is a single automatic action, not a link a human has to click through:

List-Unsubscribe: <https://example.com/unsub?id=abc123>
List-Unsubscribe-Post: List-Unsubscribe=One-Click

The RFC's own rationale is direct: anti-spam software fetches every URI in a message's headers automatically, with no user action at all. A mail client can't mechanically tell that automated fetch apart from a real click. So RFC 8058 requires an HTTPS URI (a bare mailto: doesn't qualify) that completes the unsubscribe on a single POST, with no further interaction and, critically, no redirect in the response. Redirected POSTs have historically been unreliable, so the RFC rules them out entirely.

One thing the RFC does not do: mandate a specific HTTP response code. It forbids a redirect; it doesn't require a 200. That distinction matters if you're auditing an existing endpoint against the spec rather than against a blog post's paraphrase of it.

Mistakes that fail compliance anyway

All three of these produce a working, clickable unsubscribe link. None of them satisfy RFC 8058:

<!-- Doesn't satisfy one-click, even though it's a valid link -->
List-Unsubscribe: <mailto:[email protected]>

<!-- Still non-compliant: a bare landing page requires a second click -->
List-Unsubscribe: <https://example.com/unsubscribe-preferences>
  • A landing page instead of an instant action. Google's own guidance is explicit that a one-click link pointing to a preferences or confirmation page doesn't comply, even though the URL itself is perfectly valid.
  • Redirecting the POST response. An endpoint that unsubscribes the recipient and then 302s to a "you're unsubscribed" page is doing exactly what the RFC prohibits.
  • Requiring login or confirmation first. Any extra step between the POST and the unsubscribe completing defeats the point: the whole mechanism exists so the action can happen automatically, in one request.

A compliant endpoint is plain:

// The endpoint List-Unsubscribe points to
app.post("/unsub", async (req, res) => {
  const { id } = req.query;
  await markUnsubscribed(id);

  // No redirect. A 3xx response after this POST is exactly what
  // RFC 8058 forbids ("MUST NOT return an HTTPS redirect").
  res.status(200).send("Unsubscribed");
});

The header is not the footer link

These are two different mechanisms, and one doesn't replace the other. The List-Unsubscribe header is what a mail client reads to show its own native "Unsubscribe" affordance next to the sender's name, the one-click chip Gmail and others surface directly in the inbox. The visible unsubscribe link in your email's footer is what a human actually reads, and it's perfectly fine for that link to lead to a preferences page where someone picks which lists to leave. Litmus puts it plainly: list-unsubscribe headers are not a replacement for the unsubscribe messaging and links already in your email.

The reason RFC 8058 insists on POST rather than a followable link is worth taking seriously beyond the spec text itself. In 2019, the team behind Healthchecks.io documented a real incident where Microsoft's Safe Links crawler, which renders email links in a full browser to scan for threats, executed a GET-based unsubscribe link automatically and unsubscribed real users who never clicked anything. That's the general failure mode any GET endpoint with side effects is exposed to. RFC 8058's POST-only requirement is the same fix applied specifically to unsubscribe. The same scanners quietly break magic links and verification links for the same reason, covered in link prefetching and security scanners.

Sources

How Postcraft handles this

List-Unsubscribe and List-Unsubscribe-Post are SMTP headers, set on the outgoing message by whatever sends it. That's your ESP or MTA (Postmark, SendGrid, SES, your own SMTP relay), not a template-rendering API. Postcraft renders HTML; it doesn't touch the transport layer, so this one is genuinely your sending backend's job, and most ESPs already handle it for you.

What Postcraft does own is the visible unsubscribe link in the email body itself: a per-recipient URL bound to your runtime data, rendered correctly across clients, the same variable-binding system used for every other link in a template.

Try it free