---
title: "client.Broadcasts"
description: "Every method in this namespace: its signature, its parameters, what it returns and an example."
url: "https://nextmail.sh/docs/go/reference/broadcasts"
area: "Go"
category: "Reference"
---

# client.Broadcasts

Every method in this namespace: its signature, its parameters, what it returns and an example.

## Methods

One message sent to everybody in one or more audiences, a personalised copy for each person, with unsubscribe handled for you.

### `Broadcasts.Preview`

Count who a broadcast to some audiences would reach

```go
Preview(ctx context.Context, body nextmail.Body, opts ...nextmail.RequestOption) (nextmail.Object, error)
```

Returns the numbers `Send` would work from, without sending or writing anything: `recipients`, the people a broadcast to these audiences would reach now, `unsubscribed`, the contacts skipped because they have unsubscribed, and `suppressed`, the subscribed contacts skipped because their address is on the suppression list. A contact in several of the audiences counts once.

The count is taken at the moment of the call, so contacts who join or leave before a send change it. Only `audienceIds`, `excludeAudienceIds` and `segmentId` are sent, so you can pass the same object you are about to give `Send`.

Scopes: `audiences:read`.

**Parameters**

- `audienceIds` (`[]string`, required): 1 to 10 audience ids. One that names no audience in the workspace is a 404 `audience_not_found`, and All contacts, which no broadcast can go to, is a 422 `audience_is_everyone`.
- `excludeAudienceIds` (`[]string`): Up to 10 audiences whose members are left out of the count, as `Send` leaves them out.
- `segmentId` (`string`): A saved segment that narrows the count to the contacts that match it, as `Send` narrows the broadcast.
- `nextmail.WithAPIKey` (`string`): Overrides the client's API key for this call only.

**Returns**

The `nextmail.Object` with `audienceIds` as sent, `recipients`, `unsubscribed` and `suppressed`.

**Example**

```go
reach, err := client.Broadcasts.Preview(ctx, nextmail.Body{
	"audienceIds": []string{"aud_5b1f9c3e7a2d4068c9e1f3a7"},
})
if err != nil {
	return err
}

fmt.Println(reach.Int("recipients"), reach.Int("unsubscribed"), reach.Int("suppressed"))
```

**Notes**

- Needs only `audiences:read`, so a key that cannot send can still show somebody the count.
- The SDK retries it after a network failure or a retryable status, since it changes nothing.

Also available in: API [`POST /broadcasts/preview`](https://nextmail.sh/docs/api/reference/broadcasts#post-broadcasts-preview); TypeScript [`nextmail.broadcasts.preview()`](https://nextmail.sh/docs/sdk/reference/broadcasts#preview); Python [`broadcasts.preview()`](https://nextmail.sh/docs/python/reference/broadcasts#preview); Ruby [`broadcasts.preview`](https://nextmail.sh/docs/ruby/reference/broadcasts#preview); PHP [`broadcasts->preview`](https://nextmail.sh/docs/php/reference/broadcasts#preview); Java [`broadcasts().preview`](https://nextmail.sh/docs/java/reference/broadcasts#preview); C# [`Broadcasts.PreviewAsync`](https://nextmail.sh/docs/csharp/reference/broadcasts#preview); CLI [`nextmail broadcasts preview`](https://nextmail.sh/docs/cli/reference/broadcasts#broadcasts-preview).

### `Broadcasts.Send`

Send one message to everybody in one or more audiences

```go
Send(ctx context.Context, body nextmail.Body, opts ...nextmail.RequestOption) (nextmail.Object, error)
```

Creates a broadcast: one message sent to every contact in the audiences you name, as a separate copy for each person. Every copy has exactly one recipient and no cc or bcc, so nobody sees who else it went to, and every copy is an ordinary email with its own `msg_` id, events, tracking and webhooks. `emails.list({ broadcastId })` lists them. Copies are not filed in the Sent folder, because the broadcast is the record.

The call returns straight away with the broadcast `queued`, or `scheduled` when you pass `scheduledAt`, and the sending happens in the background, 50 people at a time. Poll `Get` to follow `status` and `counts` as it goes.

Who gets it: every contact in at least one of `audienceIds`, counted once however many of them hold it, except a person who has unsubscribed and an address on the suppression list. `audienceIds` cannot name All contacts, the built-in audience of everyone the workspace has written to, because most of them never asked for its mail: that is a 422 `audience_is_everyone`. A contact added to one of the audiences after this call but before the sending reaches it is included. `counts.recipients` is the estimate taken at the call, and `Preview` returns the same count without sending.

`subject`, `html` and `text` take merge fields, filled in from each contact: `{{firstName}}`, `{{lastName}}`, `{{name}}`, `{{email}}` and `{{unsubscribeUrl}}`. Each takes a fallback after a bar, so `{{firstName|there}}` reads there for a contact with no name. The first name is the first word of the contact's name and the last name is the rest. A custom field of the contact is `{{attributes.<key>}}`, such as `{{attributes.plan|Free}}`, and reads as its fallback, or as nothing, when the contact has no such field. Values are escaped in `html`, and any other `{{…}}` is left as written. With `template`, those five values are passed as props, but only the ones the template declares, except `unsubscribeUrl`, which every template receives.

Every copy carries the one-click unsubscribe headers mail clients and the large mailbox providers look for. A body or a template that does not place `{{unsubscribeUrl}}` itself gets a short footer with the link, in English, which also names the sender and shows the postal address once `marketingPostalAddress` is set through `Settings.Update`. Following the link unsubscribes the person from all of the workspace's marketing mail: every audience they are in shows `unsubscribedAt`, `Suppressions.ListUnsubscribes` lists them, and later broadcasts and automation emails skip them, even after they are added to an audience again. Their contact and mail sent to them one message at a time are not affected.

The whole send is checked against the plan's monthly sends before anything is written. A broadcast the allowance cannot cover fails with 429 `send_quota_exceeded` and leaves nothing behind, and each copy counts as one send.

Scopes: `emails:send`, `audiences:read`.

**Parameters**

- `audienceIds` (`[]string`, required): 1 to 10 audience ids such as `aud_9f2c4b7e1a0d63d84c5f2e7b`. A contact in several of them gets one copy. An id that names no audience in the workspace is a 404 `audience_not_found` and All contacts is a 422 `audience_is_everyone`, and either way nothing is sent.
- `from` (`any`, required): Sender as `news@acme.com`, `Acme <news@acme.com>` or a map with `email` and `name`. It must be an address the key may send as, otherwise 403 `from_address_forbidden`.
- `replyTo` (`any`): Where replies go, the same for every copy.
- `subject` (`string`): Required unless a template supplies it, at most 998 characters. Takes merge fields.
- `html` (`string`): HTML body, at most 1,000,000 characters, with merge fields. Without `{{unsubscribeUrl}}` in it an unsubscribe footer is added.
- `text` (`string`): Plain text body, at most 1,000,000 characters, with merge fields. Without `{{unsubscribeUrl}}` in it an unsubscribe line is added.
- `template` (`nextmail.Body`): A stored template instead of `html` and `text`, never beside them. The merge values reach it as props it declares, such as `firstName` and `unsubscribeUrl`.
- `tracking` (`nextmail.Body`): Open and link tracking for every copy. A field left out follows the address it is sent from when that address set it, and is on otherwise.
- `tags` (`nextmail.Body`): Up to 8 tags, keys of 1 to 64 letters, digits, `_` or `-`, values up to 256 characters. Every copy carries them, plus `broadcast_id`, which the server adds.
- `excludeAudienceIds` (`[]string`): Up to 10 audiences whose members are left out, even when they are in one of `audienceIds`, such as the customers who already bought. All contacts may be named here.
- `segmentId` (`string`): A saved segment, from `Segments.Create`, that narrows the audiences: only the contacts that match its conditions get a copy. Its conditions are read when the broadcast is sent or scheduled and kept with it. An id that names no segment is a 404 `segment_not_found`.
- `utm` (`nextmail.Body`): Campaign tags added to every http and https link in the body, with `source`, `medium`, `campaign`, `term` and `content`, sent as `utm_source` and the rest. A link that already carries one keeps its own, and the unsubscribe link never gets them.
- `abTest` (`nextmail.Body`): An A/B test, with `variants`, 2 to 4 maps that each replace the `subject`, or the `html` and or `text`, of the broadcast, so an empty one keeps it, `testPercent` (5 to 50, 20 unless set), the share of people that get a variant, `metric`, `opens` or `clicks`, which picks the winner, and `waitMinutes` (30 to 4320, 240 unless set) before it is picked. Everybody else then gets the winning variant, and a template broadcast can only vary the subject.
- `scheduledAt` (`time.Time | string`): A `time.Time`, an ISO 8601 instant or a duration such as `PT2H` or `P1D`, in the future and at most 365 days out. Left out, the sending starts straight away.
- `nextmail.WithIdempotencyKey` (`string`): Your own key, 1 to 255 characters of letters, digits, `_`, `.`, `:` or `-`. Left out, the SDK makes one for the call, so its own retries never send twice. Sending the same key again answers with the broadcast it created instead of a new one; the same key with a different body is a 422 `idempotency_key_reuse`.
- `nextmail.WithAPIKey` (`string`): Sends with this key instead of the client's.

**Returns**

The `nextmail.Object`, a broadcast object plus `replayed`, with `id` (`brd_` plus 24 hex), `status` `queued` or `scheduled`, `audienceIds`, `from`, `subject`, `scheduledAt`, `createdAt` and `counts`, whose `recipients` is the estimate and whose other counts start at 0.

**Example**

```go
broadcast, err := client.Broadcasts.Send(ctx, nextmail.Body{
	"audienceIds": []string{"aud_4c1b8e2a7d9f05c36b4e8a71"},
	"from":        "Acme <news@acme.com>",
	"subject":     "{{firstName|Hello}}, the September release is out",
	"html":        "<p>Hi {{firstName|there}},</p><p>Here is what changed this month.</p><p><a href=\"{{unsubscribeUrl}}\">Unsubscribe</a></p>",
	"text":        "Hi {{firstName|there}},\n\nHere is what changed this month.\n\nUnsubscribe: {{unsubscribeUrl}}",
	"tags":        nextmail.Body{"campaign": "release-2026-09"},
	"scheduledAt": "PT2H",
})
if err != nil {
	return err
}

fmt.Println(broadcast.String("id"), broadcast.String("status"), broadcast.Bool("replayed"), broadcast.Object("counts").Int("recipients"))
```

**Notes**

- Safe to retry. Every call carries an `Idempotency-Key`, yours or one the SDK makes, so a retry after a network failure answers with the broadcast the first attempt created, with `replayed: true`, instead of sending again. Keys are scoped to the API key or app that sent them. Reusing a key with a different body is a 422 `idempotency_key_reuse`.
- Refusals: 422 `no_recipients` when the audiences are empty or everybody in them has unsubscribed or is suppressed, 422 `audience_is_everyone` when one of them is All contacts, 409 `domain_not_sendable` when the `from` domain cannot sign mail yet, 422 on `template.*` when the template does not resolve.
- No attachments, cc, bcc, translation or encryption. A body from `html` or `text` and a `template` together are refused.
- A test key (`oe_test_`) creates a broadcast whose copies are marked sent and delivered to nobody, like any test send.

Also available in: API [`POST /broadcasts`](https://nextmail.sh/docs/api/reference/broadcasts#post-broadcasts); TypeScript [`nextmail.broadcasts.send()`](https://nextmail.sh/docs/sdk/reference/broadcasts#send); Python [`broadcasts.send()`](https://nextmail.sh/docs/python/reference/broadcasts#send); Ruby [`broadcasts.send`](https://nextmail.sh/docs/ruby/reference/broadcasts#send); PHP [`broadcasts->send`](https://nextmail.sh/docs/php/reference/broadcasts#send); Java [`broadcasts().send`](https://nextmail.sh/docs/java/reference/broadcasts#send); C# [`Broadcasts.SendAsync`](https://nextmail.sh/docs/csharp/reference/broadcasts#send); CLI [`nextmail broadcasts send`](https://nextmail.sh/docs/cli/reference/broadcasts#broadcasts-send).

### `Broadcasts.List`

List one page of broadcasts, newest first

```go
List(ctx context.Context, opts ...nextmail.RequestOption) (*nextmail.Page, error)
```

Returns one page of the broadcasts in the workspace, newest first, each with live `counts`. `audienceId` keeps the ones that were sent to that audience, alone or beside others.

Paging is keyset: `nextmail.WithLimit` takes 1 to 100 and defaults to 25, and `NextCursor`, the id of the last broadcast on the page, goes back as `nextmail.WithCursor` while `HasMore` is true. Send the same `audienceId` with every page. `ListAll` and `Iterate` do that walk for you.

The individual messages are not here. List the copies of one broadcast with `emails.list({ broadcastId })`.

Scopes: `emails:read`.

**Parameters**

- `nextmail.WithAudienceID` (`string`): Only the broadcasts that included this audience. An id that names no audience answers an empty page.
- `nextmail.WithLimit` (`int`): Rows per page, a whole number from 1 to 100. The server defaults to 25.
- `nextmail.WithCursor` (`string`): The `NextCursor` from the previous page, a broadcast id. One that names no broadcast in the workspace is a 400 `invalid_cursor`.
- `nextmail.WithAPIKey` (`string`): Overrides the client's API key for this call only.

**Returns**

The `*nextmail.Page` with `Items`, `HasMore` and `NextCursor`. Each item has `id`, `status`, `audienceIds`, `from`, `subject`, `counts` and the timestamps.

**Example**

```go
page, err := client.Broadcasts.List(ctx, nextmail.WithAudienceID("aud_4c1b8e2a7d9f05c36b4e8a71"), nextmail.WithLimit(10))
if err != nil {
	return err
}

for _, broadcast := range page.Items {
	fmt.Println(broadcast.String("createdAt"), broadcast.String("subject"), broadcast.String("status"), broadcast.Object("counts").Int("sent"))
}

fmt.Println(page.HasMore, page.NextCursor)
```

**Notes**

- A key limited to particular addresses or domains lists only the broadcasts sent from an address or domain it holds.

Also available in: API [`GET /broadcasts`](https://nextmail.sh/docs/api/reference/broadcasts#get-broadcasts); TypeScript [`nextmail.broadcasts.list()`](https://nextmail.sh/docs/sdk/reference/broadcasts#list); Python [`broadcasts.list()`](https://nextmail.sh/docs/python/reference/broadcasts#list); Ruby [`broadcasts.list`](https://nextmail.sh/docs/ruby/reference/broadcasts#list); PHP [`broadcasts->list`](https://nextmail.sh/docs/php/reference/broadcasts#list); Java [`broadcasts().list`](https://nextmail.sh/docs/java/reference/broadcasts#list); C# [`Broadcasts.ListAsync`](https://nextmail.sh/docs/csharp/reference/broadcasts#list); CLI [`nextmail broadcasts list`](https://nextmail.sh/docs/cli/reference/broadcasts#broadcasts-list).

### `Broadcasts.ListAll`

Collect every broadcast into one slice

```go
ListAll(ctx context.Context, opts ...nextmail.RequestOption) ([]nextmail.Object, error)
```

Follows `NextCursor` from page to page and returns with every broadcast in the workspace, newest first, or every one sent to `audienceId` when you pass it. `limit` sets the page size of each request, not the total.

Scopes: `emails:read`.

**Parameters**

- `nextmail.WithAudienceID` (`string`): Only the broadcasts that included this audience.
- `nextmail.WithLimit` (`int`): Page size per request, from 1 to 100, defaulting to 25 on the server.
- `nextmail.WithCursor` (`string`): A broadcast id to start after.
- `nextmail.WithAPIKey` (`string`): Overrides the client's API key for every page of this walk.

**Returns**

A `[]nextmail.Object` holding every broadcast across all pages.

**Example**

```go
broadcasts, err := client.Broadcasts.ListAll(ctx, nextmail.WithLimit(100))
if err != nil {
	return err
}

for _, broadcast := range broadcasts {
	fmt.Println(broadcast.Object("counts").Int("sent"))
}
```

**Notes**

- A failure on any page fails the whole call.
- Every row carries live counts, so collecting a long history reads the copies of every broadcast in it. Use `Iterate` to stop early.
- A key limited to particular addresses or domains lists only the broadcasts sent from an address or domain it holds.

Also available in: API [`GET /broadcasts`](https://nextmail.sh/docs/api/reference/broadcasts#get-broadcasts); TypeScript [`nextmail.broadcasts.listAll()`](https://nextmail.sh/docs/sdk/reference/broadcasts#listAll); Python [`broadcasts.list_all()`](https://nextmail.sh/docs/python/reference/broadcasts#listAll); Ruby [`broadcasts.list_all`](https://nextmail.sh/docs/ruby/reference/broadcasts#listAll); PHP [`broadcasts->listAll`](https://nextmail.sh/docs/php/reference/broadcasts#listAll); Java [`broadcasts().listAll`](https://nextmail.sh/docs/java/reference/broadcasts#listAll); C# [`Broadcasts.ListAllAsync`](https://nextmail.sh/docs/csharp/reference/broadcasts#listAll).

### `Broadcasts.Iterate`

Stream broadcasts one at a time, newest first

```go
Iterate(ctx context.Context, opts ...nextmail.RequestOption) *nextmail.Iterator
```

Returns an iterator that yields broadcasts individually, newest first, and requests the next page only once the current one is drained. Breaking out of the loop stops the requests, so this is the cheap way to find the latest broadcast that matches something the filters cannot express.

Scopes: `emails:read`.

**Parameters**

- `nextmail.WithAudienceID` (`string`): Only the broadcasts that included this audience.
- `nextmail.WithLimit` (`int`): Page size per request, from 1 to 100, defaulting to 25 on the server.
- `nextmail.WithCursor` (`string`): A broadcast id to start after.
- `nextmail.WithAPIKey` (`string`): Overrides the client's API key for every page of this walk.

**Returns**

The `*nextmail.Iterator` yielding one broadcast per step.

**Example**

```go
for broadcast, err := range client.Broadcasts.Iterate(ctx).All() {
	if err != nil {
		return err
	}

	fmt.Println(broadcast.String("status"), broadcast.String("id"), broadcast.Object("counts").Int("queued"))
}
```

**Notes**

- The iterator is lazy, so an abandoned loop costs only the pages you consumed.
- A key limited to particular addresses or domains lists only the broadcasts sent from an address or domain it holds.

Also available in: API [`GET /broadcasts`](https://nextmail.sh/docs/api/reference/broadcasts#get-broadcasts); TypeScript [`nextmail.broadcasts.iterate()`](https://nextmail.sh/docs/sdk/reference/broadcasts#iterate); Python [`broadcasts.iterate()`](https://nextmail.sh/docs/python/reference/broadcasts#iterate); Ruby [`broadcasts.iterate`](https://nextmail.sh/docs/ruby/reference/broadcasts#iterate); PHP [`broadcasts->iterate`](https://nextmail.sh/docs/php/reference/broadcasts#iterate); Java [`broadcasts().iterate`](https://nextmail.sh/docs/java/reference/broadcasts#iterate); C# [`Broadcasts.IterateAsync`](https://nextmail.sh/docs/csharp/reference/broadcasts#iterate).

### `Broadcasts.Get`

Read one broadcast and how far it has got

```go
Get(ctx context.Context, id string, opts ...nextmail.RequestOption) (nextmail.Object, error)
```

Returns one broadcast with `counts` read live from its copies, which makes this the call to poll while it sends.

`status` moves from `scheduled` or `queued` to `sending` and settles on `sent` once every copy handed over has gone out or failed. It reads `sending` for as long as copies are still waiting, even after the last person was reached and `completedAt` was set. `cancelled` and `failed` are the other two ends, and on `failed` `lastError` says why: the `from` address can no longer be sent from, the template stopped resolving, the plan ran out part way, the sending itself kept failing, or not one copy could be written.

`counts.recipients` is the estimate taken when it was created. `created` is the copies written, one per person reached, `skipped` the people passed over because their address was suppressed by then, and `failedToQueue` the people whose copy could not be written. `queued`, `sending`, `sent`, `failed` and `cancelled` count the copies by the state each one is in now.

Scopes: `emails:read`.

**Parameters**

- `id` (`string`, required): A `brd_` id from `Send` or `List`.
- `nextmail.WithAPIKey` (`string`): Overrides the client's API key for this call only.

**Returns**

The `nextmail.Object` with `id`, `status`, `mode`, `source`, `audienceIds`, `from`, `subject`, `counts`, `lastError`, `scheduledAt`, `startedAt`, `completedAt`, `cancelledAt`, `createdAt` and `updatedAt`.

**Example**

```go
broadcast, err := client.Broadcasts.Get(ctx, "brd_5a8c1e3f7b2d94a06c8e1f3b")
if err != nil {
	return err
}

fmt.Println(broadcast.String("status"), broadcast.String("id"), broadcast.Object("counts").Int("sent"), broadcast.Object("counts").Int("recipients"))
```

**Notes**

- A missing broadcast fails with `*nextmail.Error` that matches `nextmail.ErrNotFound` and code `broadcast_not_found`. An id from another workspace is a 404 too.
- For who each copy went to and what happened to it, use `ListRecipients`, `GetRecipient` reads one copy with its content, and `Stats` sums it up.
- A key limited to particular addresses or domains reads only broadcasts sent from an address or domain it holds. Any other id fails with `broadcast_not_found`, as if the broadcast did not exist.

Also available in: API [`GET /broadcasts/{id}`](https://nextmail.sh/docs/api/reference/broadcasts#get-broadcasts-id); TypeScript [`nextmail.broadcasts.get()`](https://nextmail.sh/docs/sdk/reference/broadcasts#get); Python [`broadcasts.get()`](https://nextmail.sh/docs/python/reference/broadcasts#get); Ruby [`broadcasts.get`](https://nextmail.sh/docs/ruby/reference/broadcasts#get); PHP [`broadcasts->get`](https://nextmail.sh/docs/php/reference/broadcasts#get); Java [`broadcasts().get`](https://nextmail.sh/docs/java/reference/broadcasts#get); C# [`Broadcasts.GetAsync`](https://nextmail.sh/docs/csharp/reference/broadcasts#get); CLI [`nextmail broadcasts get`](https://nextmail.sh/docs/cli/reference/broadcasts#broadcasts-get).

### `Broadcasts.Stats`

Read how a broadcast performed

```go
Stats(ctx context.Context, id string, opts ...nextmail.RequestOption) (nextmail.Object, error)
```

Returns the totals and a series for one broadcast. `totals` counts copies `sent`, `delivered`, `bounced`, `complained` (reported as spam) and `failed`, `pending` for the ones still waiting, and people who `opened`, `clicked` and `unsubscribed`, with `opens` and `clicks` as event counts. `series` is sparse and oldest first: one bucket per `grain` in which something happened, counting each person once at the first time it happened to them, so it adds up to the totals.

Pass `days` or `minutes` to also read what happened lately. `window` then counts the copies delivered, bounced, reported as spam, opened, clicked and unsubscribed inside it, and `series` keeps only its buckets, while `totals` still covers the whole broadcast. Without either, `window` is null.

Scopes: `emails:read`.

**Parameters**

- `id` (`string`, required): A `brd_` id from `Send` or `List`.
- `nextmail.WithGrain` (`string`): Bucket width: `minute`, `hour` or `day`, defaulting to `hour`.
- `nextmail.WithOffsetMinutes` (`int`): Minutes east of UTC to cut the buckets in, from -840 to 840. For the local zone, pass the offset `time.Now().Zone()` reports, divided by 60.
- `nextmail.WithDays` (`int`): Reads a window of this many days too, from 1 to 1095. It starts at the beginning of its first `grain` bucket and ends now.
- `nextmail.WithMinutes` (`int`): The window in minutes, from 1 to 1576800, which wins over `days` when both are sent.
- `nextmail.WithAPIKey` (`string`): Overrides the client API key for this call only.

**Returns**

The `nextmail.Object` with `broadcastId`, `grain`, `totals`, `window` and `series`, each bucket a map with `bucket`, `delivered`, `opened`, `clicked` and `unsubscribed`. `window` is a map with `since`, `delivered`, `bounced`, `complained`, `opened`, `clicked` and `unsubscribed`, or null when no window was asked for. `links` lists the links clicked most, `clients` the mail clients and `countries` the countries people opened it from, and `abTest` how each variant of an A/B test did and which one won, or null without a test.

**Example**

```go
stats, err := client.Broadcasts.Stats(ctx, "brd_5a8c1e3f7b2d94a06c8e1f3b", nextmail.WithGrain("day"))
if err != nil {
	return err
}

fmt.Println(stats.Object("totals").Int("sent"), stats.Object("totals").Int("opened"))
```

**Notes**

- Read only, so the SDK retries it after a network failure like any other read.
- A key limited to particular addresses or domains reads only broadcasts sent from an address or domain it holds. Any other id fails with `broadcast_not_found`, as if the broadcast did not exist.

Also available in: API [`GET /broadcasts/{id}/stats`](https://nextmail.sh/docs/api/reference/broadcasts#get-broadcasts-id-stats); TypeScript [`nextmail.broadcasts.stats()`](https://nextmail.sh/docs/sdk/reference/broadcasts#stats); Python [`broadcasts.stats()`](https://nextmail.sh/docs/python/reference/broadcasts#stats); Ruby [`broadcasts.stats`](https://nextmail.sh/docs/ruby/reference/broadcasts#stats); PHP [`broadcasts->stats`](https://nextmail.sh/docs/php/reference/broadcasts#stats); Java [`broadcasts().stats`](https://nextmail.sh/docs/java/reference/broadcasts#stats); C# [`Broadcasts.StatsAsync`](https://nextmail.sh/docs/csharp/reference/broadcasts#stats); CLI [`nextmail broadcasts stats`](https://nextmail.sh/docs/cli/reference/broadcasts#broadcasts-stats).

### `Broadcasts.Analytics`

Read how broadcasts did over a time window

```go
Analytics(ctx context.Context, opts ...nextmail.RequestOption) (nextmail.Object, error)
```

Returns the numbers behind the Analytics tab of the Broadcasts page in one request: how the live broadcasts sent inside a window did, added up in `totals` and cut to `grain` in `series`, and one row per broadcast in `broadcasts` so they can be compared.

A copy counts when it was sent inside the window, and everything that happened to it afterwards counts with it, so an open today of a copy sent last week is in a 30 day window but not in a 1 day one. Test mode broadcasts are left out. `totals` and `series` add up the broadcasts named in `broadcastIds`, or every one when it is left out, while `broadcasts` always lists every broadcast in the window, newest first.

`series` is sparse and oldest first: a bucket in which nothing happened has no entry, so a chart must fill the gaps. It counts each person once, at the first time it happened to them. `grain` sets the bucket width and the key shape, `YYYY-MM-DD`, `YYYY-MM-DDTHH` or `YYYY-MM-DDTHH:MM`, and `offsetMinutes` shifts the boundaries so days break where the reader's day does. The window starts at the beginning of its oldest bucket, reported as `since`, and ends now, reported as `until`.

Scopes: `emails:read`.

**Parameters**

- `nextmail.WithBroadcastIDs` (`...string`): Up to 50 broadcast ids for `totals` and `series` to add up, sent comma separated. Leave it out, or pass an empty array, for every broadcast in the window. An id with no copy in the window adds nothing, and more than 50 is a 422.
- `nextmail.WithDays` (`int`): Window length in days, from 1 to 1095, defaulting to 30.
- `nextmail.WithMinutes` (`int`): Window length in minutes, from 1 to 1576800, which wins over `days` when both are sent.
- `nextmail.WithGrain` (`string`): Bucket width: `minute`, `hour` or `day`, defaulting to `day`.
- `nextmail.WithOffsetMinutes` (`int`): Minutes east of UTC to cut the buckets in, from -840 to 840, defaulting to 0. For the local zone, pass the offset `time.Now().Zone()` reports, divided by 60.
- `nextmail.WithAPIKey` (`string`): Overrides the client API key for this call only.

**Returns**

The `nextmail.Object` with `object` set to `broadcast_analytics`, `since`, `until`, `grain`, `offsetMinutes`, `broadcastIds`, `totals`, `series` and `broadcasts`. `totals` has `broadcasts` and the counts `BroadcastStatsTotals` has, each entry of `series` is a map with `bucket`, `sent`, `delivered`, `opened`, `clicked` and `unsubscribed`, and each entry of `broadcasts` has `id`, `subject`, `status`, `sentAt` and the same counts.

**Example**

```go
_, offset := time.Now().Zone()

analytics, err := client.Broadcasts.Analytics(ctx, nextmail.WithDays(90), nextmail.WithOffsetMinutes(offset/60))
if err != nil {
	return err
}

totals := analytics.Object("totals")
rate := 0.0

if totals.Int("delivered") > 0 {
	rate = totals.Float("opened") / totals.Float("delivered")
}

fmt.Printf("%d broadcasts, %.0f%% opened\n", totals.Int("broadcasts"), rate*100)

for _, row := range analytics.Objects("broadcasts") {
	fmt.Println(row.String("subject"), row.Int("sent"), row.Int("opened"), row.Int("clicked"))
}
```

**Notes**

- Read only, so the SDK retries it after a network failure like any other read.
- `opened`, `clicked` and `unsubscribed` count people, while `opens` and `clicks` count events.
- A key limited to particular addresses or domains reads only broadcasts sent from an address or domain it holds, and the rest are left out as if they did not exist.

Also available in: API [`GET /broadcasts/analytics`](https://nextmail.sh/docs/api/reference/broadcasts#get-broadcasts-analytics); TypeScript [`nextmail.broadcasts.analytics()`](https://nextmail.sh/docs/sdk/reference/broadcasts#analytics); Python [`broadcasts.analytics()`](https://nextmail.sh/docs/python/reference/broadcasts#analytics); Ruby [`broadcasts.analytics`](https://nextmail.sh/docs/ruby/reference/broadcasts#analytics); PHP [`broadcasts->analytics`](https://nextmail.sh/docs/php/reference/broadcasts#analytics); Java [`broadcasts().analytics`](https://nextmail.sh/docs/java/reference/broadcasts#analytics); C# [`Broadcasts.AnalyticsAsync`](https://nextmail.sh/docs/csharp/reference/broadcasts#analytics); CLI [`nextmail broadcasts analytics`](https://nextmail.sh/docs/cli/reference/broadcasts#broadcasts-analytics).

### `Broadcasts.ListRecipients`

List who a broadcast went to and what happened to each copy

```go
ListRecipients(ctx context.Context, id string, opts ...nextmail.RequestOption) (*nextmail.Page, error)
```

Returns one page of the people a broadcast went to, one row per copy, sorted by address. Each row says the copy's status, when it was sent and delivered, whether it bounced or was reported as spam, how often it was opened and clicked, and whether the person unsubscribed from one of the broadcast's audiences after it went out.

Opens and clicks leave out image proxies and link scanners, and stay 0 when the broadcast went out with tracking off. `emailId` is the copy's `msg_` id, which `GetRecipient` reads with its content and `Emails.Get` reads as a sent email.

Scopes: `emails:read`.

**Parameters**

- `id` (`string`, required): A `brd_` id from `Send` or `List`.
- `nextmail.WithFilter` (`string`): Keeps one group: `pending`, `sent`, `delivered`, `opened`, `not_opened` (sent and never opened), `clicked`, `bounced`, `complained`, `failed` (failed or cancelled) or `unsubscribed`. `BROADCAST_RECIPIENT_FILTERS` names them.
- `nextmail.WithQ` (`string`): Searches the address and the name, ignoring case.
- `nextmail.WithLimit` (`int`): Page size, from 1 to 200. The server defaults to 50.
- `nextmail.WithCursor` (`string`): The `NextCursor` of the previous page. Send the same `filter` and `q` with it.
- `nextmail.WithAPIKey` (`string`): Overrides the client API key for this call only.

**Returns**

The `*nextmail.Page` with `Items`, `HasMore` and `NextCursor`. Each item has `emailId`, `contactId`, `email`, `name`, `status`, `sentAt`, `deliveredAt`, `bouncedAt`, `complainedAt`, `failure`, `opens`, `firstOpenAt`, `clicks`, `firstClickAt` and `unsubscribedAt`.

**Example**

```go
page, err := client.Broadcasts.ListRecipients(ctx, "brd_5a8c1e3f7b2d94a06c8e1f3b", nextmail.WithFilter("bounced"))
if err != nil {
	return err
}

for _, recipient := range page.Items {
	fmt.Println(recipient.String("email"), recipient.String("bouncedAt"))
}

fmt.Println(page.HasMore, page.NextCursor)
```

**Notes**

- A missing broadcast fails with `*nextmail.Error` with code `broadcast_not_found`.
- A key limited to particular addresses or domains reads only broadcasts sent from an address or domain it holds. Any other id fails with `broadcast_not_found`, as if the broadcast did not exist.

Also available in: API [`GET /broadcasts/{id}/recipients`](https://nextmail.sh/docs/api/reference/broadcasts#get-broadcasts-id-recipients); TypeScript [`nextmail.broadcasts.listRecipients()`](https://nextmail.sh/docs/sdk/reference/broadcasts#listRecipients); Python [`broadcasts.list_recipients()`](https://nextmail.sh/docs/python/reference/broadcasts#listRecipients); Ruby [`broadcasts.list_recipients`](https://nextmail.sh/docs/ruby/reference/broadcasts#listRecipients); PHP [`broadcasts->listRecipients`](https://nextmail.sh/docs/php/reference/broadcasts#listRecipients); Java [`broadcasts().listRecipients`](https://nextmail.sh/docs/java/reference/broadcasts#listRecipients); C# [`Broadcasts.ListRecipientsAsync`](https://nextmail.sh/docs/csharp/reference/broadcasts#listRecipients); CLI [`nextmail broadcasts list-recipients`](https://nextmail.sh/docs/cli/reference/broadcasts#broadcasts-list-recipients).

### `Broadcasts.ListAllRecipients`

Collect everybody a broadcast went to into one slice

```go
ListAllRecipients(ctx context.Context, id string, opts ...nextmail.RequestOption) ([]nextmail.Object, error)
```

Walks every page of `ListRecipients` and returns with every copy of the broadcast, sorted by address. One request per page, with the same `filter` and `q` on each.

Scopes: `emails:read`.

**Parameters**

- `id` (`string`, required): A `brd_` id from `Send` or `List`.
- `nextmail.WithFilter` (`string`): Keeps one group: `pending`, `sent`, `delivered`, `opened`, `not_opened` (sent and never opened), `clicked`, `bounced`, `complained`, `failed` (failed or cancelled) or `unsubscribed`. `BROADCAST_RECIPIENT_FILTERS` names them.
- `nextmail.WithQ` (`string`): Searches the address and the name, ignoring case.
- `nextmail.WithLimit` (`int`): Page size for each request, from 1 to 200. The server defaults to 50.
- `nextmail.WithCursor` (`string`): Starts the walk after this cursor instead of the first page.
- `nextmail.WithAPIKey` (`string`): Overrides the client API key for every page of this walk.

**Returns**

A `[]nextmail.Object` holding every copy that matches.

**Example**

```go
unopened, err := client.Broadcasts.ListAllRecipients(ctx, "brd_5a8c1e3f7b2d94a06c8e1f3b", nextmail.WithFilter("not_opened"))
if err != nil {
	return err
}

for _, recipient := range unopened {
	fmt.Println(recipient.String("email"))
}
```

**Notes**

- If any page fails the call fails and the rows already fetched are discarded.
- A key limited to particular addresses or domains reads only broadcasts sent from an address or domain it holds. Any other id fails with `broadcast_not_found`, as if the broadcast did not exist.

Also available in: API [`GET /broadcasts/{id}/recipients`](https://nextmail.sh/docs/api/reference/broadcasts#get-broadcasts-id-recipients); TypeScript [`nextmail.broadcasts.listAllRecipients()`](https://nextmail.sh/docs/sdk/reference/broadcasts#listAllRecipients); Python [`broadcasts.list_all_recipients()`](https://nextmail.sh/docs/python/reference/broadcasts#listAllRecipients); Ruby [`broadcasts.list_all_recipients`](https://nextmail.sh/docs/ruby/reference/broadcasts#listAllRecipients); PHP [`broadcasts->listAllRecipients`](https://nextmail.sh/docs/php/reference/broadcasts#listAllRecipients); Java [`broadcasts().listAllRecipients`](https://nextmail.sh/docs/java/reference/broadcasts#listAllRecipients); C# [`Broadcasts.ListAllRecipientsAsync`](https://nextmail.sh/docs/csharp/reference/broadcasts#listAllRecipients).

### `Broadcasts.IterateRecipients`

Walk everybody a broadcast went to, one copy at a time

```go
IterateRecipients(ctx context.Context, id string, opts ...nextmail.RequestOption) *nextmail.Iterator
```

Yields every copy of the broadcast one at a time, fetching the next page only when the loop asks for it, sorted by address. Breaking out of the loop stops the requests.

Scopes: `emails:read`.

**Parameters**

- `id` (`string`, required): A `brd_` id from `Send` or `List`.
- `nextmail.WithFilter` (`string`): Keeps one group: `pending`, `sent`, `delivered`, `opened`, `not_opened` (sent and never opened), `clicked`, `bounced`, `complained`, `failed` (failed or cancelled) or `unsubscribed`. `BROADCAST_RECIPIENT_FILTERS` names them.
- `nextmail.WithQ` (`string`): Searches the address and the name, ignoring case.
- `nextmail.WithLimit` (`int`): Page size for each request, from 1 to 200. The server defaults to 50.
- `nextmail.WithCursor` (`string`): Starts after this cursor instead of the first page.
- `nextmail.WithAPIKey` (`string`): Overrides the client API key for every page of this walk.

**Returns**

The `*nextmail.Iterator` yielding one copy per step.

**Example**

```go
for recipient, err := range client.Broadcasts.IterateRecipients(ctx, "brd_5a8c1e3f7b2d94a06c8e1f3b", nextmail.WithFilter("clicked")).All() {
	if err != nil {
		return err
	}

	fmt.Println(recipient.String("email"), recipient.Int("clicks"))
}
```

**Notes**

- Memory stays flat however large the broadcast, because only one page is held at a time.
- A key limited to particular addresses or domains reads only broadcasts sent from an address or domain it holds. Any other id fails with `broadcast_not_found`, as if the broadcast did not exist.

Also available in: API [`GET /broadcasts/{id}/recipients`](https://nextmail.sh/docs/api/reference/broadcasts#get-broadcasts-id-recipients); TypeScript [`nextmail.broadcasts.iterateRecipients()`](https://nextmail.sh/docs/sdk/reference/broadcasts#iterateRecipients); Python [`broadcasts.iterate_recipients()`](https://nextmail.sh/docs/python/reference/broadcasts#iterateRecipients); Ruby [`broadcasts.iterate_recipients`](https://nextmail.sh/docs/ruby/reference/broadcasts#iterateRecipients); PHP [`broadcasts->iterateRecipients`](https://nextmail.sh/docs/php/reference/broadcasts#iterateRecipients); Java [`broadcasts().iterateRecipients`](https://nextmail.sh/docs/java/reference/broadcasts#iterateRecipients); C# [`Broadcasts.IterateRecipientsAsync`](https://nextmail.sh/docs/csharp/reference/broadcasts#iterateRecipients).

### `Broadcasts.GetRecipient`

Read one person's copy of a broadcast

```go
GetRecipient(ctx context.Context, id string, emailID string, opts ...nextmail.RequestOption) (nextmail.Object, error)
```

Returns one copy: the same row `ListRecipients` gives, plus the `subject`, `html` and `text` exactly as that person received them, with the merge fields filled in and their own unsubscribe link. The HTML is from before open and click tracking was added.

Scopes: `emails:read`.

**Parameters**

- `id` (`string`, required): A `brd_` id from `Send` or `List`.
- `emailID` (`string`, required): The `emailId` of the copy, from `ListRecipients`.
- `nextmail.WithAPIKey` (`string`): Overrides the client API key for this call only.

**Returns**

The `nextmail.Object`: `emailId`, `contactId`, `email`, `name`, `status`, `sentAt`, `deliveredAt`, `bouncedAt`, `complainedAt`, `failure`, `opens`, `firstOpenAt`, `clicks`, `firstClickAt` and `unsubscribedAt`, plus `subject`, `html` and `text`.

**Example**

```go
content, err := client.Broadcasts.GetRecipient(ctx, "brd_5a8c1e3f7b2d94a06c8e1f3b", "msg_01dad25067bc4dac966d515d")
if err != nil {
	return err
}

fmt.Println(content.String("subject"), content.String("deliveredAt"))
```

**Notes**

- An `emailId` that is not a copy of this broadcast fails with code `recipient_not_found`.
- A key limited to particular addresses or domains reads only broadcasts sent from an address or domain it holds. Any other id fails with `broadcast_not_found`, as if the broadcast did not exist.

Also available in: API [`GET /broadcasts/{id}/recipients/{emailId}`](https://nextmail.sh/docs/api/reference/broadcasts#get-broadcasts-id-recipients-emailid); TypeScript [`nextmail.broadcasts.getRecipient()`](https://nextmail.sh/docs/sdk/reference/broadcasts#getRecipient); Python [`broadcasts.get_recipient()`](https://nextmail.sh/docs/python/reference/broadcasts#getRecipient); Ruby [`broadcasts.get_recipient`](https://nextmail.sh/docs/ruby/reference/broadcasts#getRecipient); PHP [`broadcasts->getRecipient`](https://nextmail.sh/docs/php/reference/broadcasts#getRecipient); Java [`broadcasts().getRecipient`](https://nextmail.sh/docs/java/reference/broadcasts#getRecipient); C# [`Broadcasts.GetRecipientAsync`](https://nextmail.sh/docs/csharp/reference/broadcasts#getRecipient); CLI [`nextmail broadcasts get-recipient`](https://nextmail.sh/docs/cli/reference/broadcasts#broadcasts-get-recipient).

### `Broadcasts.Cancel`

Stop a broadcast that is scheduled, queued or still sending

```go
Cancel(ctx context.Context, id string, opts ...nextmail.RequestOption) (nextmail.Object, error)
```

Stops a broadcast that is `scheduled`, `queued` or `sending`, including one that has reached everybody while some copies are still waiting to go. Nobody else is added, and every copy still waiting is cancelled. A copy already being handed over finishes, and copies that have gone cannot be recalled, so `counts.sent` keeps them and `counts.cancelled` shows what was stopped.

Once every copy has gone out there is nothing left to stop, and the call fails with 409 `broadcast_not_cancellable`. A `failed` broadcast with copies still waiting can be cancelled to stop them, and one with nothing waiting is refused the same way. Cancelling a broadcast that is already cancelled returns it as it stands, so the call is safe to repeat, and the SDK retries it after a network failure.

Scopes: `emails:send`.

**Parameters**

- `id` (`string`, required): The `brd_` id to cancel.
- `nextmail.WithAPIKey` (`string`): Cancels with this key instead of the client's.

**Returns**

The `nextmail.Object` in its new state, `status` `cancelled` with `cancelledAt` set and the copies counted by where each one ended up.

**Example**

```go
cancelled, err := client.Broadcasts.Cancel(ctx, "brd_5a8c1e3f7b2d94a06c8e1f3b")
if err != nil {
	return err
}

fmt.Println(cancelled.String("status"), cancelled.Object("counts").Int("cancelled"))
```

**Notes**

- Cancelling a scheduled broadcast before `scheduledAt` sends nothing at all.
- A cancelled broadcast stays cancelled. There is no resume, so send again to the audiences that still need it.
- A key limited to particular addresses or domains cancels only broadcasts sent from an address or domain it holds. Any other id fails with `broadcast_not_found`, as if the broadcast did not exist.

Also available in: API [`POST /broadcasts/{id}/cancel`](https://nextmail.sh/docs/api/reference/broadcasts#post-broadcasts-id-cancel); TypeScript [`nextmail.broadcasts.cancel()`](https://nextmail.sh/docs/sdk/reference/broadcasts#cancel); Python [`broadcasts.cancel()`](https://nextmail.sh/docs/python/reference/broadcasts#cancel); Ruby [`broadcasts.cancel`](https://nextmail.sh/docs/ruby/reference/broadcasts#cancel); PHP [`broadcasts->cancel`](https://nextmail.sh/docs/php/reference/broadcasts#cancel); Java [`broadcasts().cancel`](https://nextmail.sh/docs/java/reference/broadcasts#cancel); C# [`Broadcasts.CancelAsync`](https://nextmail.sh/docs/csharp/reference/broadcasts#cancel); CLI [`nextmail broadcasts cancel`](https://nextmail.sh/docs/cli/reference/broadcasts#broadcasts-cancel).

### `Broadcasts.CreateDraft`

Save a broadcast as a draft without sending it

```go
CreateDraft(ctx context.Context, body nextmail.Body, opts ...nextmail.RequestOption) (nextmail.Object, error)
```

Saves a broadcast with `status` `draft`. Nothing is sent, nothing counts against the plan and the audiences may still be empty, so a draft can be written over several sittings. `Update` changes it, `SendDraft` sends it or schedules it, and `Get` returns what it holds in `content`.

The body takes the fields `Send` takes, except `scheduledAt`, which belongs to `SendDraft`. Only `from` is required. The sender, the audiences and a template are checked as they are saved.

Scopes: `emails:send`, `audiences:read`.

**Parameters**

- `from` (`string or nextmail.Body`, required): Sender as `news@acme.com` or `Acme <news@acme.com>`, or `nextmail.Body` with `email` and `name`. It must be an address the key may send as, otherwise 403 `from_address_forbidden`.
- `audienceIds` (`[]string`): Up to 10 audience ids. Left out or empty, the draft has no audience yet and `SendDraft` refuses it until `Update` gives it one.
- `excludeAudienceIds` (`[]string`): Up to 10 audiences whose members are left out, even when they are in one of `audienceIds`.
- `segmentId` (`string`): A saved segment that narrows the audiences when the draft is sent. It has to exist when the draft is saved and again when it is sent.
- `replyTo` (`string or nextmail.Body`): Where replies go, the same for every copy.
- `subject` (`string`): At most 998 characters, with merge fields. Needed before sending unless a template supplies it.
- `html` (`string`): HTML body, at most 1,000,000 characters, with merge fields.
- `text` (`string`): Plain text body, at most 1,000,000 characters, with merge fields.
- `template` (`nextmail.Body`): A stored template instead of `html` and `text`, with `id` and, optionally, `version`, `props` and `slots`.
- `tracking` (`nextmail.Body`): Open and link tracking for every copy, with `opens` and `clicks`.
- `tags` (`nextmail.Body`): Up to 8 tags every copy carries.
- `utm` (`nextmail.Body`): Campaign tags added to every http and https link in the body, with `source`, `medium`, `campaign`, `term` and `content`, sent as `utm_source` and the rest. A link that already carries one keeps its own, and the unsubscribe link never gets them.
- `abTest` (`nextmail.Body`): An A/B test, as `Send` takes it.
- `nextmail.WithAPIKey` (`string`): Overrides the client's API key for this call only.

**Returns**

The `nextmail.Object`, the broadcast with `status` `draft`, counts at 0 and the saved fields in `content`.

**Example**

```go
draft, err := client.Broadcasts.CreateDraft(ctx, nextmail.Body{
	"from":        "Acme <news@acme.com>",
	"audienceIds": []string{"aud_4c1b8e2a7d9f05c36b4e8a71"},
	"subject":     "The October release",
	"text":        "Hi {{firstName|there}}, here is what changed this month.",
	"utm":         nextmail.Body{"source": "newsletter", "medium": "email", "campaign": "october-release"},
})
if err != nil {
	return err
}

fmt.Println(draft.String("id"), draft.String("status"))
```

**Notes**

- A draft is listed by `List` beside the broadcasts that went out, with `status` `draft`.
- Refusals are 404 `audience_not_found`, 422 `audience_is_everyone` when `audienceIds` names All contacts, 403 `from_address_forbidden`, and 422 on `template.*` when the template does not resolve.

Also available in: API [`POST /broadcasts/drafts`](https://nextmail.sh/docs/api/reference/broadcasts#post-broadcasts-drafts); TypeScript [`nextmail.broadcasts.createDraft()`](https://nextmail.sh/docs/sdk/reference/broadcasts#createDraft); Python [`broadcasts.create_draft()`](https://nextmail.sh/docs/python/reference/broadcasts#createDraft); Ruby [`broadcasts.create_draft`](https://nextmail.sh/docs/ruby/reference/broadcasts#createDraft); PHP [`broadcasts->createDraft`](https://nextmail.sh/docs/php/reference/broadcasts#createDraft); Java [`broadcasts().createDraft`](https://nextmail.sh/docs/java/reference/broadcasts#createDraft); C# [`Broadcasts.CreateDraftAsync`](https://nextmail.sh/docs/csharp/reference/broadcasts#createDraft); CLI [`nextmail broadcasts create-draft`](https://nextmail.sh/docs/cli/reference/broadcasts#broadcasts-create-draft).

### `Broadcasts.Update`

Change a draft, or a scheduled broadcast before it starts

```go
Update(ctx context.Context, id string, patch nextmail.Body, opts ...nextmail.RequestOption) (nextmail.Object, error)
```

A partial update: a field you leave out keeps what it holds, and `nil` clears `replyTo`, `html`, `text`, `template` or `utm`. Sending any of `html`, `text` or `template` replaces the body as a whole.

A draft takes every change and stays a draft. A `scheduled` broadcast takes changes until its sending starts, and each change is checked the way `Send` checks a new one, so `counts.recipients` is counted again. `scheduledAt` moves a scheduled broadcast to another time. Once a broadcast is queued, sending or finished, the call fails with 409 `broadcast_not_editable`.

Scopes: `emails:send`, `audiences:read`.

**Parameters**

- `id` (`string`, required): The `brd_` id of a draft or of a scheduled broadcast.
- `audienceIds` (`[]string`): The new audiences, replacing the old list, up to 10.
- `excludeAudienceIds` (`[]string`): The new list of audiences whose members are left out.
- `segmentId` (`string or nil`): A saved segment that narrows the audiences. `nil` takes it away.
- `from` (`string or nextmail.Body`): A new sender the key may send as.
- `replyTo` (`string, nextmail.Body or nil`): Where replies go. `nil` takes it away.
- `subject` (`string`): A new subject, with merge fields.
- `html` (`string or nil`): A new HTML body.
- `text` (`string or nil`): A new plain text body.
- `template` (`nextmail.Body or nil`): A stored template instead of `html` and `text`.
- `tracking` (`nextmail.Body`): Open and link tracking for every copy.
- `tags` (`nextmail.Body`): The new tags, replacing the old ones.
- `utm` (`nextmail.Body or nil`): New campaign tags for the links. `nil` takes them away.
- `abTest` (`nextmail.Body or nil`): A new A/B test, as `Send` takes it. `nil` takes it away.
- `scheduledAt` (`string or time.Time`): A new start for a scheduled broadcast: an ISO 8601 instant or a duration such as `PT2H`. A draft refuses it with 422 `invalid_parameter`, since `SendDraft` schedules a draft.
- `nextmail.WithAPIKey` (`string`): Overrides the client's API key for this call only.

**Returns**

The `nextmail.Object`, the broadcast as it stands after the change, with `content`.

**Example**

```go
draft, err := client.Broadcasts.CreateDraft(ctx, nextmail.Body{"from": "news@acme.com", "subject": "Draft"})
if err != nil {
	return err
}

updated, err := client.Broadcasts.Update(ctx, draft.String("id"), nextmail.Body{
	"audienceIds": []string{"aud_4c1b8e2a7d9f05c36b4e8a71"},
	"subject":     "Doors open on Friday",
	"text":        "Hi {{firstName|there}}, doors open at nine.",
})
if err != nil {
	return err
}

fmt.Println(updated.String("status"), updated.String("subject"))
```

**Notes**

- A key limited to particular addresses or domains changes only broadcasts sent from an address or domain it holds. Any other id fails with `broadcast_not_found`.
- Changing a scheduled broadcast can fail the way `Send` fails: 422 `no_recipients`, 429 `send_quota_exceeded`, 409 `stream_paused`.

Also available in: API [`PATCH /broadcasts/{id}`](https://nextmail.sh/docs/api/reference/broadcasts#patch-broadcasts-id); TypeScript [`nextmail.broadcasts.update()`](https://nextmail.sh/docs/sdk/reference/broadcasts#update); Python [`broadcasts.update()`](https://nextmail.sh/docs/python/reference/broadcasts#update); Ruby [`broadcasts.update`](https://nextmail.sh/docs/ruby/reference/broadcasts#update); PHP [`broadcasts->update`](https://nextmail.sh/docs/php/reference/broadcasts#update); Java [`broadcasts().update`](https://nextmail.sh/docs/java/reference/broadcasts#update); C# [`Broadcasts.UpdateAsync`](https://nextmail.sh/docs/csharp/reference/broadcasts#update); CLI [`nextmail broadcasts update`](https://nextmail.sh/docs/cli/reference/broadcasts#broadcasts-update).

### `Broadcasts.SendDraft`

Send a draft now, or schedule it

```go
SendDraft(ctx context.Context, id string, body nextmail.Body, opts ...nextmail.RequestOption) (nextmail.Object, error)
```

Turns a draft into a broadcast that goes out: `queued` straight away, or `scheduled` when you pass `scheduledAt`. The draft is checked the way `Send` checks a new broadcast, so it needs an audience, a body, a subject or a template that supplies one, somebody to reach, and room in the plan for every copy.

A broadcast that is not a draft fails with 409 `broadcast_not_draft`, so calling it twice never sends twice.

Scopes: `emails:send`, `audiences:read`.

**Parameters**

- `id` (`string`, required): The `brd_` id of the draft.
- `scheduledAt` (`string or time.Time`): An ISO 8601 instant or a duration such as `PT2H`, in the future and at most 365 days out. Left out, the sending starts straight away.
- `nextmail.WithAPIKey` (`string`): Overrides the client's API key for this call only.

**Returns**

The `nextmail.Object`, the broadcast with `status` `queued` or `scheduled` and `counts.recipients` estimated at the call.

**Example**

```go
draft, err := client.Broadcasts.CreateDraft(ctx, nextmail.Body{
	"from":        "Acme <news@acme.com>",
	"audienceIds": []string{"aud_4c1b8e2a7d9f05c36b4e8a71"},
	"subject":     "Doors open on Friday",
	"text":        "Hi {{firstName|there}}, doors open at nine.",
})
if err != nil {
	return err
}

sent, err := client.Broadcasts.SendDraft(ctx, draft.String("id"), nextmail.Body{"scheduledAt": "PT2H"})
if err != nil {
	return err
}

fmt.Println(sent.String("status"), sent.String("scheduledAt"))
```

**Notes**

- Refusals are 409 `broadcast_not_draft`, 422 `no_recipients`, 422 `invalid_parameter` when the draft has no body or no subject, 429 `send_quota_exceeded`, and 409 `stream_paused` while the broadcast lane of the workspace is paused.
- The SDK does not retry it after a network failure. Read the broadcast with `Get` before calling again.

Also available in: API [`POST /broadcasts/{id}/send`](https://nextmail.sh/docs/api/reference/broadcasts#post-broadcasts-id-send); TypeScript [`nextmail.broadcasts.sendDraft()`](https://nextmail.sh/docs/sdk/reference/broadcasts#sendDraft); Python [`broadcasts.send_draft()`](https://nextmail.sh/docs/python/reference/broadcasts#sendDraft); Ruby [`broadcasts.send_draft`](https://nextmail.sh/docs/ruby/reference/broadcasts#sendDraft); PHP [`broadcasts->sendDraft`](https://nextmail.sh/docs/php/reference/broadcasts#sendDraft); Java [`broadcasts().sendDraft`](https://nextmail.sh/docs/java/reference/broadcasts#sendDraft); C# [`Broadcasts.SendDraftAsync`](https://nextmail.sh/docs/csharp/reference/broadcasts#sendDraft); CLI [`nextmail broadcasts send-draft`](https://nextmail.sh/docs/cli/reference/broadcasts#broadcasts-send-draft).

### `Broadcasts.Duplicate`

Copy a broadcast into a new draft

```go
Duplicate(ctx context.Context, id string, opts ...nextmail.RequestOption) (nextmail.Object, error)
```

Makes a new draft from any broadcast, with the same sender, audiences, left-out audiences, subject, body or template, tracking, tags and campaign tags. The time it was scheduled for is not copied. The original is not changed, and nothing is sent until `SendDraft`.

Scopes: `emails:send`, `audiences:read`.

**Parameters**

- `id` (`string`, required): The `brd_` id to copy.
- `nextmail.WithAPIKey` (`string`): Overrides the client's API key for this call only.

**Returns**

The `nextmail.Object`, the new draft with its own `brd_` id, `status` `draft` and `content`.

**Example**

```go
copied, err := client.Broadcasts.Duplicate(ctx, "brd_5e8a2c1f9b3d74e06a5c2f81")
if err != nil {
	return err
}

fmt.Println(copied.String("id"), copied.String("status"))
```

**Notes**

- The sender, the audiences and the template are checked again as the copy is saved, so a copy of an old broadcast can fail with 403 `from_address_forbidden` or 404 `audience_not_found`.

Also available in: API [`POST /broadcasts/{id}/duplicate`](https://nextmail.sh/docs/api/reference/broadcasts#post-broadcasts-id-duplicate); TypeScript [`nextmail.broadcasts.duplicate()`](https://nextmail.sh/docs/sdk/reference/broadcasts#duplicate); Python [`broadcasts.duplicate()`](https://nextmail.sh/docs/python/reference/broadcasts#duplicate); Ruby [`broadcasts.duplicate`](https://nextmail.sh/docs/ruby/reference/broadcasts#duplicate); PHP [`broadcasts->duplicate`](https://nextmail.sh/docs/php/reference/broadcasts#duplicate); Java [`broadcasts().duplicate`](https://nextmail.sh/docs/java/reference/broadcasts#duplicate); C# [`Broadcasts.DuplicateAsync`](https://nextmail.sh/docs/csharp/reference/broadcasts#duplicate); CLI [`nextmail broadcasts duplicate`](https://nextmail.sh/docs/cli/reference/broadcasts#broadcasts-duplicate).

### `Broadcasts.Resend`

Send a broadcast again to the people who did not open it

```go
Resend(ctx context.Context, id string, body nextmail.Body, opts ...nextmail.RequestOption) (nextmail.Object, error)
```

Creates a new broadcast with the same content for the people the first one reached and who have not opened it, optionally under a new subject. Somebody who has unsubscribed since, or whose address is now suppressed, is skipped. The new broadcast carries `content.resendOf`, and counts against the plan like any send.

The first broadcast has to have finished going out and to have tracked opens. Otherwise the call fails with 409 `resend_unavailable`.

Scopes: `emails:send`, `audiences:read`.

**Parameters**

- `id` (`string`, required): The `brd_` id of the broadcast that went out.
- `subject` (`string`): A new subject for the second try, with merge fields. Left out, the first subject is used.
- `scheduledAt` (`string or time.Time`): When to start, in the future and at most 365 days out. Left out, the sending starts straight away.
- `nextmail.WithAPIKey` (`string`): Overrides the client's API key for this call only.

**Returns**

The `nextmail.Object`, the new broadcast, `queued` or `scheduled`, with `counts.recipients` holding the people who had not opened.

**Example**

```go
second, err := client.Broadcasts.Resend(ctx, "brd_5e8a2c1f9b3d74e06a5c2f81", nextmail.Body{
	"subject":     "In case you missed it: doors open on Friday",
	"scheduledAt": "P2D",
})
if err != nil {
	return err
}

fmt.Println(second.String("id"), second.Object("counts").Int("recipients"))
```

**Notes**

- Opens are counted from the tracking pixel, so somebody whose mail app blocks images can look like they never opened. Give a second try some days, and do not send it more than once.
- Refusals are 409 `resend_unavailable`, 422 `no_recipients` when everybody opened it, 429 `send_quota_exceeded`, and 409 `stream_paused`.

Also available in: API [`POST /broadcasts/{id}/resend`](https://nextmail.sh/docs/api/reference/broadcasts#post-broadcasts-id-resend); TypeScript [`nextmail.broadcasts.resend()`](https://nextmail.sh/docs/sdk/reference/broadcasts#resend); Python [`broadcasts.resend()`](https://nextmail.sh/docs/python/reference/broadcasts#resend); Ruby [`broadcasts.resend`](https://nextmail.sh/docs/ruby/reference/broadcasts#resend); PHP [`broadcasts->resend`](https://nextmail.sh/docs/php/reference/broadcasts#resend); Java [`broadcasts().resend`](https://nextmail.sh/docs/java/reference/broadcasts#resend); C# [`Broadcasts.ResendAsync`](https://nextmail.sh/docs/csharp/reference/broadcasts#resend); CLI [`nextmail broadcasts resend`](https://nextmail.sh/docs/cli/reference/broadcasts#broadcasts-resend).

### `Broadcasts.SendTest`

Send a test copy of a broadcast to yourself or a few people

```go
SendTest(ctx context.Context, body nextmail.Body, opts ...nextmail.RequestOption) (nextmail.Object, error)
```

Sends one copy of a broadcast to up to five addresses, to read it before it goes to an audience. It goes to the account address of the person the key or app acts for, the workspace owner for an API key, unless `to` names others. The merge fields are filled from the contact that has the address when there is one and from a sample name otherwise, the subject starts with `[Test]`, the unsubscribe footer is added as it would be and its link does nothing. Opens and clicks are not tracked, and `utm` is applied to the links.

No broadcast is created and nobody joins an audience. Each copy counts as one send.

Scopes: `emails:send`.

**Parameters**

- `from` (`string or nextmail.Body`, required): The sender, an address the key may send as.
- `to` (`[]string`): 1 to 5 addresses. Left out, the test goes to the account address of the person the key or app acts for.
- `replyTo` (`string or nextmail.Body`): Where replies go.
- `subject` (`string`): Required unless a template supplies it, with merge fields.
- `html` (`string`): HTML body with merge fields.
- `text` (`string`): Plain text body with merge fields.
- `template` (`nextmail.Body`): A stored template instead of `html` and `text`.
- `utm` (`nextmail.Body`): Campaign tags added to the links, as the broadcast would add them.
- `nextmail.WithAPIKey` (`string`): Overrides the client's API key for this call only.

**Returns**

The `nextmail.Object` with the `msg_` id of each copy in `emailIds` and the addresses in `to`.

**Example**

```go
test, err := client.Broadcasts.SendTest(ctx, nextmail.Body{
	"from":    "Acme <news@acme.com>",
	"to":      []string{"me@acme.com"},
	"subject": "{{firstName|Hello}}, doors open on Friday",
	"html":    "<p>Hi {{firstName|there}}, doors open at nine.</p>",
})
if err != nil {
	return err
}

fmt.Println(test.Strings("emailIds"), test.Strings("to"))
```

**Notes**

- The SDK does not retry it, since a retry would send the test again.

Also available in: API [`POST /broadcasts/test`](https://nextmail.sh/docs/api/reference/broadcasts#post-broadcasts-test); TypeScript [`nextmail.broadcasts.sendTest()`](https://nextmail.sh/docs/sdk/reference/broadcasts#sendTest); Python [`broadcasts.send_test()`](https://nextmail.sh/docs/python/reference/broadcasts#sendTest); Ruby [`broadcasts.send_test`](https://nextmail.sh/docs/ruby/reference/broadcasts#sendTest); PHP [`broadcasts->sendTest`](https://nextmail.sh/docs/php/reference/broadcasts#sendTest); Java [`broadcasts().sendTest`](https://nextmail.sh/docs/java/reference/broadcasts#sendTest); C# [`Broadcasts.SendTestAsync`](https://nextmail.sh/docs/csharp/reference/broadcasts#sendTest); CLI [`nextmail broadcasts send-test`](https://nextmail.sh/docs/cli/reference/broadcasts#broadcasts-send-test).
