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

# Email Channel

> Read and change an agent's inbound email address settings, and the public Resend webhook that delivers mail to it.

# Email Channel

An agent with the email channel turned on has an address,
`<slug>@<inbound domain>`. It answers every email it receives in the same
thread, and each thread is one conversation.

The address is issued on the first save and never changes. Settings are stored
on the agent's channel row; there is no separate secret.

<Note>
  All API requests require a valid JWT token in the `Authorization: Bearer <token>` header. The API Gateway decodes the JWT and forwards auth context (`user-id`, `organization-id`, `user-email`, `x-platform-role`, `x-org-role`) as headers to downstream services.
</Note>

Both endpoints need **manage** access to the agent: an org owner, admin or
member, a viewer with a grant, or a platform superadmin. Another
organization's agent answers `404`.

## Get Email Settings

<ParamField method="GET" path="/api/bot/bots/{botId}/email/config" />

### Response (200)

<ResponseField name="enabled" type="boolean">Whether the agent answers email now.</ResponseField>
<ResponseField name="slug" type="string | null">The address's local part. `null` until the first save.</ResponseField>
<ResponseField name="address" type="string | null">The full address. `null` without a slug, or when the platform has no inbound domain.</ResponseField>
<ResponseField name="platformConfigured" type="boolean">`false` until a platform admin sets `RESEND_EMAIL_API_KEY`, `RESEND_EMAIL_WEBHOOK_SECRET` and `EMAIL_INBOUND_DOMAIN`. The channel cannot be turned on before then.</ResponseField>
<ResponseField name="fromName" type="string">The name on the `From` line. The agent's name when none is set.</ResponseField>
<ResponseField name="accessMode" type="string">`anyone` or `allowlist`.</ResponseField>
<ResponseField name="allowedSenders" type="string[]">Lowercased addresses (`ada@example.com`) and domains (`@example.com`). Used only in `allowlist` mode.</ResponseField>

```json theme={null}
{
  "enabled": true,
  "slug": "acme-support-3f9a1",
  "address": "acme-support-3f9a1@mail.example.com",
  "platformConfigured": true,
  "fromName": "Acme Support",
  "accessMode": "allowlist",
  "allowedSenders": ["@acme.com", "ada@example.com"]
}
```

## Update Email Settings

<ParamField method="PUT" path="/api/bot/bots/{botId}/email/config" />

Only the fields you send change. `allowedSenders`, when sent, replaces the whole
list. The first call creates the address, whether or not it turns the channel
on. Every change is written to the organization's audit log as
`email_channel.update`.

<ParamField body="enabled" type="boolean">Turn answering on or off. Turning on needs the platform keys (see `platformConfigured`).</ParamField>
<ParamField body="fromName" type="string">Display name on replies. Up to 100 characters; no line breaks, quotes, `<`, `>` or `\`. An empty string means "use the agent's name".</ParamField>
<ParamField body="accessMode" type="string">`anyone`, or `allowlist` to accept email only from `allowedSenders`. Other senders get one short refusal per day.</ParamField>
<ParamField body="allowedSenders" type="string[]">Up to 500 entries, each a full address or `@domain` (exact domain — subdomains do not match). Trimmed, lowercased and de-duplicated.</ParamField>

```json theme={null}
{ "enabled": true, "fromName": "Acme Support" }
```

### Response (200)

The updated settings, in the same shape as **Get Email Settings**.

### Errors

| Status | `code` | When |
| - | - | - |
| `400` | `email_config_invalid` | Empty body, an unknown field, or a `fromName` with forbidden characters. |
| `400` | `email_allowlist_invalid` | An entry is not an address or `@domain`. The message names up to three. |
| `400` | `email_allowlist_empty` | The result would be `allowlist` mode with no entries, which accepts nobody. |
| `401` | — | No authentication. |
| `403` | — | No manage access to the agent. |
| `404` | — | The agent does not exist in your organization. |
| `503` | `email_not_configured` | `enabled: true` while the platform keys are not set. |

## Inbound Webhook (Resend)

<ParamField method="POST" path="/api/public/channels/email/webhook" />

Public, no user authentication. Resend calls it for the `email.received`
event; you do not call it yourself. The **Svix signature** (`svix-id`,
`svix-timestamp`, `svix-signature`), checked against
`RESEND_EMAIL_WEBHOOK_SECRET` on the exact bytes received, is the only gate.

| Status | When |
| - | - |
| `200` | Queued, or not for this platform (another event type, or no recipient on the inbound domain). |
| `400` | The signed body is not JSON. |
| `401` | Missing headers, a bad signature, a timestamp outside 5 minutes, or no secret configured. |
| `5xx` | The email could not be queued. Resend retries. |

The webhook carries no body; the worker fetches the email from Resend, then
answers it in the thread. Automatic emails (auto-replies, bounces, mailing
lists, no-reply senders, other agents on the platform) are never answered.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.