# Send one message to a list of people

A transactional message goes to an address you already have in hand. Marketing mail works the other way round: you keep a list of people and send one message to all of them. That list is an **audience**, the people on it are **contacts**, and the message is a **broadcast**.

Everything here belongs to one product. For the transactional side — one message to one address, triggered by something that happened — see [How system email works](/ship/mail).

## Put people in an audience

An audience is a named bucket: a name of 1 to 200 characters, and nothing else. You create them, rename them, list them and delete them.

**MCP.** [`mail_audience_create`](/reference/mcp-tools/mail_audience_create), [`mail_audience_list`](/reference/mcp-tools/mail_audience_list), [`mail_audience_update`](/reference/mcp-tools/mail_audience_update), [`mail_audience_delete`](/reference/mcp-tools/mail_audience_delete).

A contact is a person you may send marketing mail to:

| Field | What it holds |
|---|---|
| `email` | The address, stored trimmed and lower-cased |
| `properties` | Your own key/value pairs — `first_name`, `plan`, anything you like |
| `unsubscribed` | Whether this person has opted out |
| `audienceId` | The audience the contact belongs to |

`properties` is free-form: keys are yours to choose and values are ordinary JSON. Two of them mean something — `first_name` and `last_name` are offered to templates — and the rest are simply carried along.

**MCP.** [`mail_contact_create`](/reference/mcp-tools/mail_contact_create), [`mail_contact_list`](/reference/mcp-tools/mail_contact_list), [`mail_contact_get`](/reference/mcp-tools/mail_contact_get), [`mail_contact_update`](/reference/mcp-tools/mail_contact_update), [`mail_contact_delete`](/reference/mcp-tools/mail_contact_delete).

Two rules worth knowing before you design your lists:

- **Updating a contact replaces the whole `properties` object** rather than merging into it, so send back the fields you want to keep. The same call sets or clears `unsubscribed`.
- **A contact belongs to exactly one audience.** An address may appear in several audiences, but only once in each, so the same person can be on both "product updates" and "beta testers" as two separate contacts, each with its own properties and its own opt-out state. There is no way to move a contact between audiences: create it in the other audience and delete the original.

Deleting an audience deletes the contacts in it.

Contacts are listed one audience at a time, between 1 and 100 at a time (50 by default) with a cursor for the next page, and can be narrowed to only the unsubscribed or only the subscribed.

## Send a broadcast

A broadcast is one message to one audience. It is created as a **draft** and sends nothing until you queue it.

1. **Create the draft.** It needs a name, the audience to send to, and a `from` address at one of your verified domains — the same rule as any other send, see [Verify a sending domain](/ship/mail/domains). It may also carry reply-to addresses and custom headers.
2. **Give it content.** Choose one of two forms and do not mix them: **inline** — a subject, plus HTML or plain text (or both); or **a template** — the id of a published template with the variables to render it with, see [Write a template](/ship/mail/templates).
3. **Queue it.** This is the point of no return.

**MCP.** [`mail_broadcast_create`](/reference/mcp-tools/mail_broadcast_create), [`mail_broadcast_update`](/reference/mcp-tools/mail_broadcast_update), [`mail_broadcast_queue`](/reference/mcp-tools/mail_broadcast_queue), [`mail_broadcast_get`](/reference/mcp-tools/mail_broadcast_get), [`mail_broadcast_list`](/reference/mcp-tools/mail_broadcast_list).

While it is a draft, a broadcast can be edited freely and deleted. Once it leaves that state neither is possible: editing or deleting a queued, sent, failed or cancelled broadcast is refused.

### What queuing does

The broadcast moves to `queued` and is then fanned out: the audience is walked and one ordinary email is created per eligible contact. Two kinds of contact are skipped:

- Anyone whose `unsubscribed` flag is set is not even considered.
- Anyone whose address is on the product's suppression list is recorded as skipped and no message is created — see [Keep your mail deliverable](/ship/mail/deliverability).

Each message that is created goes through the normal send path from there, with its own status and its own events, and each carries a per-recipient unsubscribe header. Because a broadcast is many messages they do not all leave at once: the audience is worked through in pages, and the broadcast becomes `sent` when the last of them has been handed on.

When the content comes from a template, each contact's message is rendered with the broadcast's own variables plus four filled in for you:

| Variable | Value |
|---|---|
| `FIRST_NAME` | The contact's `first_name` property, or empty |
| `LAST_NAME` | The contact's `last_name` property, or empty |
| `EMAIL` | The contact's address |
| `UNSUBSCRIBE_URL` | That contact's unsubscribe link |

`UNSUBSCRIBE_URL` is what lets you put a visible "unsubscribe" link in the body of the message itself, next to the one the mail client offers.

### Cancelling it

A broadcast can be cancelled while it is a draft or while it is queued. Cancelling a draft simply stops it ever going out. **Cancelling one that is already being fanned out stops it between pages**: messages already created are on their way and are not recalled, but no further contact is reached. Anything already sent, failed or cancelled cannot be cancelled.

If the fan-out itself cannot complete, the broadcast ends as `failed` and keeps the reason it failed with.

**MCP.** [`mail_broadcast_cancel`](/reference/mcp-tools/mail_broadcast_cancel), [`mail_broadcast_delete`](/reference/mcp-tools/mail_broadcast_delete).

## Read what happened

Each broadcast reports on itself. **MCP:** [`mail_broadcast_stats`](/reference/mcp-tools/mail_broadcast_stats).

| Field | Meaning |
|---|---|
| `recipients` | Contacts a message was created for |
| `suppressed` | Contacts skipped because the address was suppressed |
| `failed` | Contacts whose message could not be created |
| `delivered` | Messages the receiving servers accepted |
| `bounced` | Messages that were rejected |
| `opened`, `clicked` | Opens and link clicks, when tracking is on for the sending domain |

The first three add up to the contacts the fan-out considered. The rest arrive afterwards, as the outcomes come back, so they keep rising for a while after the broadcast is `sent`. For an event per message rather than a total, see [Receive mail webhooks](/ship/mail/webhooks).

## Handle unsubscribes

Every message created by a broadcast carries the two headers that let a mail client offer a one-click unsubscribe of its own: `List-Unsubscribe`, holding a link unique to that contact, and `List-Unsubscribe-Post`, which tells the client the link can be triggered directly. The link is signed, so it cannot be forged or edited to point at someone else, and it does not expire.

Opening the link in a browser shows a short confirmation page with a button and **changes nothing by itself** — mailbox scanners follow links in mail, and a link that unsubscribed people merely for being visited would opt out people who never asked to leave. The opt-out happens only when the button is pressed, or when a mail client triggers the link directly. Using the same link twice does nothing the second time.

When it does happen, two things follow at once:

1. The contact is marked `unsubscribed`, so no later broadcast to that audience includes them.
2. Their address is added to the product's suppression list with the reason `unsubscribe`, so no later message of any kind reaches it.

> **That second step reaches your transactional mail too.** An opt-out from a marketing message stops your receipts and password resets to the same address. If a recipient asks to come back, remove the address from the suppression list **and** clear the contact's `unsubscribed` flag — both sides have to be undone.

**MCP.** [`mail_suppression_list`](/reference/mcp-tools/mail_suppression_list), [`mail_suppression_remove`](/reference/mcp-tools/mail_suppression_remove).

## Next steps

- [See where your audience came from](/acquire/tracking/identity): the people Lessly Tracking identified are the addresses worth putting in an audience.
- [Read the attribution reports](/acquire/tracking/reports): `utm_medium=email` is its own channel, so a broadcast's revenue is attributable.
- [Send one email](/ship/mail/sending): the transactional side, one message to one address.
- [Verify a sending domain](/ship/mail/domains): the `from` address a broadcast needs.
- [Keep your mail deliverable](/ship/mail/deliverability): the suppression list an unsubscribe writes into.
