> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mailchannels.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Unsubscribe

> Learn how to give recipients a one-click way to opt out.

MailChannels supports two ways to let recipients opt out of future email:

* An **unsubscribe link** that you place inside the message body.
* **List-Unsubscribe headers** that email clients render as a native unsubscribe control.

## Unsubscribe link

Insert the `mc-unsubscribe-url` placeholder anywhere in your `text/html` or `text/plain` content. At render time, MailChannels
replaces it with a unique URL that opens a one-click unsubscribe page hosted by MailChannels.

To use the placeholder:

* The content part must set `template_type` to `mustache`.
* Each personalization must contain exactly one recipient, so the generated URL is unique to that recipient.

<Info>
  Only `text/html` and `text/plain` content parts are supported. The placeholder is ignored in other content types.
</Info>

### HTML content

Place the placeholder in the `href` of an `<a>` element so it renders correctly across email clients:

<CodeGroup>
  ```bash cURL theme={null}
  #!/usr/bin/env bash
  set -u
  : "${MAILCHANNELS_API_KEY:?Set MAILCHANNELS_API_KEY before running}"
  : "${FROM_EMAIL:?Set FROM_EMAIL (must be on a Domain-Lockdown-authorized domain)}"
  : "${TO_EMAIL:?Set TO_EMAIL}"

  curl -X POST https://api.mailchannels.net/tx/v1/send \
    -H "Content-Type: application/json" \
    -H "X-Api-Key: $MAILCHANNELS_API_KEY" \
    -d @- <<JSON
  {
    "personalizations": [
      { "to": [{ "email": "$TO_EMAIL", "name": "Recipient" }] }
    ],
    "from": {
      "email": "$FROM_EMAIL",
      "name": "Your Name"
    },
    "subject": "Hello from MailChannels",
    "content": [
      {
        "type": "text/html",
        "value": "<html><body><a href='{{mc-unsubscribe-url}}'>Unsubscribe</a></body></html>",
        "template_type": "mustache"
      }
    ]
  }
  JSON
  ```

  ```javascript Node.js theme={null}
  import { MailChannels } from "mailchannels-sdk";

  const { MAILCHANNELS_API_KEY, FROM_EMAIL, TO_EMAIL } = process.env;
  if (!MAILCHANNELS_API_KEY) throw new Error("Set MAILCHANNELS_API_KEY before running");
  if (!FROM_EMAIL) throw new Error("Set FROM_EMAIL (must be on a Domain-Lockdown-authorized domain)");
  if (!TO_EMAIL) throw new Error("Set TO_EMAIL");

  const mailchannels = new MailChannels(MAILCHANNELS_API_KEY);

  const { data, error } = await mailchannels.emails.send({
    from: { email: FROM_EMAIL, name: "Your Name" },
    to: { email: TO_EMAIL, name: "Recipient" },
    subject: "Hello from MailChannels",
    html: "<html><body><a href='{{mc-unsubscribe-url}}'>Unsubscribe</a></body></html>",
    template: { type: "mustache" },
  });

  if (error) {
    console.error("Send failed:", error);
    process.exit(1);
  }
  console.log(data);
  ```

  ```python Python theme={null}
  import os
  import sys

  import mailchannels

  if not os.environ.get("MAILCHANNELS_API_KEY"):
      sys.exit("Set MAILCHANNELS_API_KEY before running")

  from_email = os.environ.get("FROM_EMAIL")
  to_email = os.environ.get("TO_EMAIL")
  if not from_email:
      sys.exit("Set FROM_EMAIL (must be on a Domain-Lockdown-authorized domain)")
  if not to_email:
      sys.exit("Set TO_EMAIL")

  response = mailchannels.Emails.send(
      {
          "from": {"email": from_email, "name": "Your Name"},
          "subject": "Hello from MailChannels",
          "content": [
              {
                  "type": "text/html",
                  "value": "<html><body><a href='{{mc-unsubscribe-url}}'>Unsubscribe</a></body></html>",
                  "template_type": "mustache",
              },
          ],
          "personalizations": [
              {"to": [{"email": to_email, "name": "Recipient"}]},
          ],
      }
  )

  print(response)
  ```

  ```php PHP theme={null}
  <?php

  require_once __DIR__ . '/vendor/autoload.php';

  use MailChannels\Client;

  $api_key    = getenv('MAILCHANNELS_API_KEY') or exit("Error: MAILCHANNELS_API_KEY is not set\n");
  $from_email = getenv('FROM_EMAIL') or exit("Error: FROM_EMAIL is not set\n");
  $to_email   = getenv('TO_EMAIL') or exit("Error: TO_EMAIL is not set\n");

  $client = new Client(apiKey: $api_key);

  $response = $client->emails->send([
      'from'    => ['email' => $from_email, 'name' => 'Your Name'],
      'subject' => 'Hello from MailChannels',
      'content' => [
          [
              'type'          => 'text/html',
              'value'         => "<html><body><a href='{{mc-unsubscribe-url}}'>Unsubscribe</a></body></html>",
              'template_type' => 'mustache',
          ],
      ],
      'personalizations' => [
          ['to' => [['email' => $to_email, 'name' => 'Recipient']]],
      ],
  ]);

  print_r($response->toArray());
  ```
</CodeGroup>

### Plain text content

Include the placeholder inline:

<CodeGroup>
  ```bash cURL theme={null}
  #!/usr/bin/env bash
  set -u
  : "${MAILCHANNELS_API_KEY:?Set MAILCHANNELS_API_KEY before running}"
  : "${FROM_EMAIL:?Set FROM_EMAIL (must be on a Domain-Lockdown-authorized domain)}"
  : "${TO_EMAIL:?Set TO_EMAIL}"

  curl -X POST https://api.mailchannels.net/tx/v1/send \
    -H "Content-Type: application/json" \
    -H "X-Api-Key: $MAILCHANNELS_API_KEY" \
    -d @- <<JSON
  {
    "personalizations": [
      { "to": [{ "email": "$TO_EMAIL", "name": "Recipient" }] }
    ],
    "from": {
      "email": "$FROM_EMAIL",
      "name": "Your Name"
    },
    "subject": "Hello from MailChannels",
    "content": [
      {
        "type": "text/plain",
        "value": "To unsubscribe, visit: {{mc-unsubscribe-url}}",
        "template_type": "mustache"
      }
    ]
  }
  JSON
  ```

  ```javascript Node.js theme={null}
  import { MailChannels } from "mailchannels-sdk";

  const { MAILCHANNELS_API_KEY, FROM_EMAIL, TO_EMAIL } = process.env;
  if (!MAILCHANNELS_API_KEY) throw new Error("Set MAILCHANNELS_API_KEY before running");
  if (!FROM_EMAIL) throw new Error("Set FROM_EMAIL (must be on a Domain-Lockdown-authorized domain)");
  if (!TO_EMAIL) throw new Error("Set TO_EMAIL");

  const mailchannels = new MailChannels(MAILCHANNELS_API_KEY);

  const { data, error } = await mailchannels.emails.send({
    from: { email: FROM_EMAIL, name: "Your Name" },
    to: { email: TO_EMAIL, name: "Recipient" },
    subject: "Hello from MailChannels",
    text: "To unsubscribe, visit: {{mc-unsubscribe-url}}",
    template: { type: "mustache" },
  });

  if (error) {
    console.error("Send failed:", error);
    process.exit(1);
  }
  console.log(data);
  ```

  ```python Python theme={null}
  import os
  import sys

  import mailchannels

  if not os.environ.get("MAILCHANNELS_API_KEY"):
      sys.exit("Set MAILCHANNELS_API_KEY before running")

  from_email = os.environ.get("FROM_EMAIL")
  to_email = os.environ.get("TO_EMAIL")
  if not from_email:
      sys.exit("Set FROM_EMAIL (must be on a Domain-Lockdown-authorized domain)")
  if not to_email:
      sys.exit("Set TO_EMAIL")

  response = mailchannels.Emails.send(
      {
          "from": {"email": from_email, "name": "Your Name"},
          "subject": "Hello from MailChannels",
          "content": [
              {
                  "type": "text/plain",
                  "value": "To unsubscribe, visit: {{mc-unsubscribe-url}}",
                  "template_type": "mustache",
              },
          ],
          "personalizations": [
              {"to": [{"email": to_email, "name": "Recipient"}]},
          ],
      }
  )

  print(response)
  ```

  ```php PHP theme={null}
  <?php

  require_once __DIR__ . '/vendor/autoload.php';

  use MailChannels\Client;

  $api_key    = getenv('MAILCHANNELS_API_KEY') or exit("Error: MAILCHANNELS_API_KEY is not set\n");
  $from_email = getenv('FROM_EMAIL') or exit("Error: FROM_EMAIL is not set\n");
  $to_email   = getenv('TO_EMAIL') or exit("Error: TO_EMAIL is not set\n");

  $client = new Client(apiKey: $api_key);

  $response = $client->emails->send([
      'from'    => ['email' => $from_email, 'name' => 'Your Name'],
      'subject' => 'Hello from MailChannels',
      'content' => [
          [
              'type'          => 'text/plain',
              'value'         => 'To unsubscribe, visit: {{mc-unsubscribe-url}}',
              'template_type' => 'mustache',
          ],
      ],
      'personalizations' => [
          ['to' => [['email' => $to_email, 'name' => 'Recipient']]],
      ],
  ]);

  print_r($response->toArray());
  ```
</CodeGroup>

## List-Unsubscribe headers

Clients such as Gmail and Apple Mail render a native **Unsubscribe** control when a message carries `List-Unsubscribe`
and `List-Unsubscribe-Post` headers. We automatically add both headers when the `transactional` field is set to **false** in
the send request — **unless you include your own `List-Unsubscribe` header, in which case we use yours and don't add ours.**

When `transactional` is false, the following conditions must also be met:

* Each personalization contains **exactly one recipient**
* The email is [DKIM signed](/email-api/configuring-dkim)
