# Unsubscribe links

Marketing mail needs a way for recipients to opt out, and bulk senders are required by Gmail and Yahoo to offer [one-click unsubscribe](/docs/knowledge-base/deliverability/gmail-yahoo-requirements). A recipient can take two paths: the unsubscribe button the mailbox provider renders from your `List-Unsubscribe` header, and a link in the message body. Bird wires up both on marketing sends, reports each as a webhook event, and acts on them by [suppressing](/docs/guides/email/suppressions) the address. This guide covers both paths, the hosted unsubscribe page behind them, the events Bird fires, and how suppression closes the loop.

## Set the category first

Unsubscribes only mean something for mail a recipient can opt out of, so the first thing to get right is the [category](/docs/guides/email/categories). A send is `category: "marketing"` by default, so marketing, newsletter, and announcement mail is treated correctly with no extra work: a recipient who opts out is suppressed with reason `unsubscribe`, which blocks `marketing` sends but still lets `transactional` mail (password resets, receipts) through. Set `category: "transactional"` explicitly for operational mail, so it is never gated by an unsubscribe and carries no opt-out affordance.

## One-click List-Unsubscribe (RFC 8058)

The one-click mechanism is the unsubscribe button mailbox providers render in their own UI, driven by two headers on your message:

```text
List-Unsubscribe: <https://yourapp.com/unsubscribe?token=abc123>, <mailto:unsubscribe@yourdomain.com?subject=unsubscribe>
List-Unsubscribe-Post: List-Unsubscribe=One-Click
```

`List-Unsubscribe` lists where to send the opt-out: an HTTPS URL, a `mailto:`, or both. `List-Unsubscribe-Post: List-Unsubscribe=One-Click` is what makes it _one-click_ (RFC 8058): the provider sends a plain `POST` to the HTTPS URL when the recipient taps unsubscribe, with no confirmation page. The endpoint must accept that unauthenticated `POST` and record the opt-out without requiring the recipient to log in or confirm; that is the contract Gmail and Yahoo check for.

On a `marketing` send Bird sets these headers for you, pointing at a Bird-managed opt-out endpoint, so the compliant one-click button appears with no work on your side. This is true however you send: a broadcast from the dashboard, or a `marketing` message through the API (`POST /v1/email/messages`), which is the default category. Because Bird owns the header on marketing mail, supplying your own `List-Unsubscribe` or `List-Unsubscribe-Post` on a `marketing` send is rejected with a `422`. On a `transactional` send Bird adds no unsubscribe header, and you may set your own through the [`headers`](/docs/guides/email/sending-email#reply-to-and-custom-headers) field if you have a reason to.

When a recipient uses the provider's button, Bird fires an [`email.list_unsubscribed`](/docs/guides/email/events) event.

## The in-body unsubscribe link

The other path is a visible unsubscribe link in the message body, the opt-out marketing mail is expected to carry on top of the header button. Bird adds one to your `marketing` sends automatically, in both the HTML and plain-text parts, so a recipient always has a link to click without you building or hosting anything. You are free to add your own link as well (for example to a preference center you host), and the platform link remains as the compliant floor.

### Choosing where the link goes

By default the link arrives as a small footer appended to the end of the body. To place it yourself, put the reserved `{{unsubscribe_url}}` variable where the link belongs:

```html
<p>
  You received this because you subscribed to our newsletter. You can {{unsubscribe_url}} at any
  time.
</p>
```

When the body contains `{{unsubscribe_url}}`, Bird renders the unsubscribe link there instead of appending the footer: in HTML, an anchor whose text is "unsubscribe"; in the plain-text part, the raw opt-out URL. The link is substituted into the outgoing copy only, so reading the message back through the API returns your original content with the variable intact.

When a recipient unsubscribes through the in-body link, Bird fires an [`email.unsubscribed`](/docs/guides/email/events#emailunsubscribed) event, distinct from `email.list_unsubscribed` so you can tell an in-body opt-out apart from a provider-button one.

## The hosted unsubscribe page

Both paths terminate on a Bird-hosted confirmation page. The in-body link records the opt-out as part of the click and then lands there; the one-click button records it through the provider's `POST`. Loading the page by its URL alone records nothing, and the page offers a confirm button for the rare visit where no opt-out was recorded yet, so a shared or forwarded page link can't unsubscribe anyone by itself.

Brand it on the [**Unsubscribe page**](https://bird.com/dashboard/w/email/unsubscribe-page) page (**Email → Unsubscribe page**) in the dashboard: set the sender name recipients see (it falls back to your organization name when unset) and the background, text, and button colors, with a live example link to preview the result. Suppression records created through this page carry `origin: unsubscribe_link` (the [Suppressions guide](/docs/guides/email/suppressions) covers the origin vocabulary).

## The webhook events

Bird delivers both unsubscribe events to your [webhook endpoint](/docs/guides/webhooks) in the standard event envelope. Subscribe to them the same way you subscribe to any other email event; no separate unsubscribe webhook exists:

| Event                     | Fires when                                                                       |
| :------------------------ | :------------------------------------------------------------------------------- |
| `email.unsubscribed`      | The recipient clicked the unsubscribe link in your message body.                 |
| `email.list_unsubscribed` | The recipient used the mailbox provider's one-click button (`List-Unsubscribe`). |

Both carry the identity base every email event carries (`email_id`, `recipient_id`, `workspace_id`, the `recipient` address and its `recipient_role`, plus the `tags` and `metadata` from the original send), so you can reconcile the opt-out against your own records without an extra lookup. Use these events to update preferences in your own system: flip the subscription off, log the opt-out, stop including the address in your sends. The full payload shapes and the rest of the email event catalog are in the [events reference](/docs/guides/email/events).

## Suppression closes the loop

You don't have to act on the webhook to stop Bird from mailing an unsubscribed recipient again; Bird does it automatically. Both `email.unsubscribed` and `email.list_unsubscribed` add the address to your workspace [suppression list](/docs/guides/email/suppressions) with reason `unsubscribe` and `applies_to: non_transactional`:

- Future **`marketing`** sends to the address are rejected up front with `email.rejected` and `rejection_reason: "recipient_suppressed"`.
- Future **`transactional`** sends still go through: an unsubscribe is a preference about marketing mail, not a dead address.

That makes the webhook events a mirror for your own database rather than the thing that protects your reputation; Bird already blocks the send. If you ever need to inspect or undo an unsubscribe, the suppression record carries `source_email_id` and `source_recipient_id` linking back to the message that caused it, and you can remove it through the [suppressions API](/docs/guides/email/suppressions#managing-suppressions-via-the-api).

## Next steps

- [Categories](/docs/guides/email/categories): why `marketing` is what makes an unsubscribe take effect
- [Suppressions](/docs/guides/email/suppressions): the list unsubscribes land on, and how to manage it
- [Email events](/docs/guides/email/events): the full `email.unsubscribed` / `email.list_unsubscribed` payloads and the rest of the catalog
- [Gmail & Yahoo requirements](/docs/knowledge-base/deliverability/gmail-yahoo-requirements): where one-click unsubscribe is required for bulk senders
- [Webhooks](/docs/guides/webhooks): subscribing an endpoint, signature verification, and retries