# Before Send Hook

> Skip a broadcast for some people, or change the subject and add content for each person, just before the email is sent.

Source: https://sendbroadcast.net/docs/plugins-hook-before-send

> Coming in Broadcast 3.0. Until then, this page applies only to the Upcoming (edge) build.

Use this hook to skip a broadcast for some people, or to change it for each person.

This is a strong hook, so it is a sensitive permission. The admin sees **Change emails before they are sent**. Add it only if a merge tag cannot do the job.

## How it works

Broadcast calls your function once for each batch of up to 100 people, just before it sends to them. It works for broadcasts only, not for sequence emails.

## Full example: VIP subject

This plugin skips people who have paused, and it gives VIPs their own subject and a closing line.

`manifest.json`:

```json
{
  "id": "local.vip-subject",
  "name": "VIP subject",
  "version": "1.0.0",
  "requires": { "broadcast": ">=3.0.0 <4.0.0", "pluginApi": "1" },
  "permissions": {
    "subscribers": "read"
  },
  "hooks": {
    "beforeSend": true
  }
}
```

`dist/main.js`:

```javascript
export default definePlugin({
  async beforeSend({ subject, subscribers }) {
    const changes = {};
    for (const person of subscribers) {
      if (person.custom_data?.paused === true) {
        changes[person.id] = { skip: true };
      } else if (person.custom_data?.vip === true) {
        changes[person.id] = {
          subject: `For our VIPs: ${subject}`,
          append_html: "<p>Thank you for being a VIP.</p>",
        };
      }
    }
    return changes;
  },
});
```

The `subscribers` permission is here because the plugin reads `custom_data`.

## What you get and return

You get this:

```json
{
  "broadcast_id": 45,
  "subject": "October news",
  "subscribers": [
    { "id": 12, "email": "ada@example.com", "first_name": "Ada", "last_name": null, "custom_data": { "vip": true } }
  ]
}
```

You return an object with the subscriber ID as the key. Leave out the people you do not change.

| Field | Effect |
|---|---|
| `skip: true` | The person does not get this broadcast |
| `subject` | Replaces the subject, up to 998 characters |
| `prepend_html` | Adds HTML before the body |
| `append_html` | Adds HTML after the body |
| `headers` | Adds email headers, for example `{ "X-Campaign": "spring" }`. Only names that start with `X-`, up to 10, one line each |

Broadcast ignores everything else. You cannot change who gets the email, who it is from, the unsubscribe link or any header that does not start with `X-`.

Broadcast cleans your HTML, and each addition can be up to 10,000 characters. The added HTML goes only in the HTML version of the email, not the plain text version.

If two plugins answer for one person, any `skip` wins, the last subject wins and HTML additions are joined.

## Common mistakes

**You expect it to fail closed.** If your hook fails or takes more than 5 seconds, the email goes out unchanged. So never use this hook as the only guard for something that must not be sent.

**You make one call per person.** You have 5 seconds for 100 people. Use the data you are given.

**You forget `subscribers` permission.** Without it, each person has only `id` and `email`, so `custom_data` is `undefined`.

**You test with a test send.** Plugin hooks do not run in test sends. Send to a small segment.
