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

# Letting AI Agents Send Email Safely

> How to give an AI agent access to Lettr over MCP with a restricted API key, a sandbox rehearsal, IP limits, and idempotent sends.

This guide covers how to give an AI agent access to Lettr over MCP with no more reach than its job needs. The controls are the key's permission level, a sandbox key for rehearsal, IP restrictions and idempotency keys for retries. The last section combines them into one setup.

***

## What Can Go Wrong

A script sends exactly what its code says, while an agent decides what to send from instructions and data that nobody fully controls. That opens risks a script does not have:

| Risk | Example |
| - | - |
| **Too much reach** | An agent that only needed to send a receipt can also delete templates or send a campaign |
| **Wrong recipient** | A prompt, a document or a support ticket the agent read steers it toward an address you never intended |
| **Duplicate sends** | A timeout makes the agent retry, and the first attempt had already gone out |
| **Leaked credential** | The key sits in plain text in a client config file, a CI log or a shared chat |
| **Untested behavior** | The first real run of a new prompt is also the first time anyone sees what it sends |

A better prompt does not remove any of these. The controls below are limits Lettr enforces, so they hold whatever the agent decides.

***

## How Agents Reach Lettr

Lettr hosts a remote [MCP](https://docs.lettr.com/learn/mcp/introduction.md) server at `https://app.lettr.com/mcp`. It accepts either a Lettr sign-in (OAuth) or a `lttr_` API key sent as `Authorization: Bearer lttr_...`. Each tool maps to the same operation as a REST endpoint.

The two ways of connecting give you very different control:

| | API key | OAuth |
| - | - | - |
| **Acts as** | A team | A person |
| **Scoped access** | Yes, by the key's permission level | No, full account access |
| **Needs a human** | No | Yes, once, in a browser |
| **Best for** | Unattended agents, CI, restricted access | Your own interactive use |

For an agent you want to restrict, use a key. OAuth gives the assistant everything you can do in the dashboard, so it suits supervised, personal use rather than an autonomous agent.

***

## Give the Agent the Least Access It Needs

### Choose a Permission Level

Every key is one of two permission levels, picked when you create it under **API Keys**:

| Level | What the key can do |
| - | - |
| **Full access** | Everything the API offers: send, read, manage templates, domains, webhooks, audience, campaigns |
| **Sending only** | Send email, SMS and WhatsApp, and nothing else |

A Sending only key that calls any other endpoint gets `403` with `error_code: insufficient_scope`. The level is a preset of scopes, and you cannot pick scopes one by one. See [Permissions](https://docs.lettr.com/learn/api-keys/permissions.md) for the full scope list.

For an agent whose job is to send, such as a support assistant that emails order updates or a workflow that sends a template, use Sending only.

### What the Agent Sees through MCP

The server checks the key on every request and hides tools the key has no scope for, so an agent never offers an action it cannot perform. Each tool needs the same scope as its REST endpoint.

| Key | Tools the agent sees |
| - | - |
| **Sending only** | `send_email`, `send_template_email`, `schedule_email`, `cancel_scheduled_email`, plus `current_team` and `list_teams`. Tools such as `send_event`, which can start automations, are absent because the key has no `events:send` scope. |
| **Full access** | Everything above, plus read and write tools for emails, templates, domains, webhooks, audience, campaigns and automations, and `send_event` |

Two details matter for safety:

* A tool that declares no scope is unavailable to every key. A new tool cannot reach key-authenticated agents by accident.
* `list_api_keys` and `browse_api_logs` are never available to a key. An agent holding a key cannot list your other keys.

After a key's permission level changes, the agent loses the affected tools on its next call, even if its client still has the old tool list cached.

> [!WARNING]
>
> A Full access key lets an agent call `send_campaign`, which sends to a campaign's whole audience, and delete tools such as `delete_template`. If an agent does not need these, do not give it a Full access key.

***

## Rehearse With a Sandbox Key

Before an agent touches real recipients, run it on a sandbox key. Create one under **API Keys** by setting **Type** to **Sandbox**. Sandbox keys start with `lttr_sandbox_`.

A sandbox key behaves like a live key with its email sends contained:

* **Recipients are replaced.** Every `to`, `cc` and `bcc` address becomes the email address of the user who created the key, whatever the agent asked for.
* **The sender domain is replaced.** The `from` domain becomes `dev.uselettr.com`, so no verified sending domain is needed.
* **Most writes are blocked.** On REST, a sandbox key can send email and read, but creating, updating or deleting templates, domains, webhooks and similar resources is refused, and so are SMS and WhatsApp sends. On MCP, any tool that needs a `:write` scope is unavailable to a sandbox key.
* **Email sends are isolated.** Sandbox email sends use a separate subaccount, do not count toward your sending quota, and do not trigger your webhooks.

Because every email goes to the key owner, an agent whose prompt is still being tuned can loop or hallucinate an address without a real recipient receiving anything.

One difference between REST and MCP matters here. Over REST, a sandbox key cannot call `POST /events`. Over MCP, `send_event` stays available to a Full access sandbox key, and the event it sends is not redirected, so it can start automations that email real recipients. A Sending only sandbox key does not hold the `events:send` scope, so `send_event` is not available to it.

For that reason, rehearse on a sandbox key with Sending only permissions. It holds only the sending scopes, so the agent has the send and schedule tools and nothing that acts on your audience or automations.

To see what the agent sent, open the **Events** page in the dashboard and turn on the **Sandbox** toggle. Sandbox events are not shown without it.

> [!NOTE]
>
> Sandbox keys have their own rate limits, separate from your team's live traffic. See [Sandbox API Keys](https://docs.lettr.com/learn/api-keys/sandbox.md#rate-limits) for the figures.

***

## Restrict Where the Key Can Be Used

A key can be limited to specific source addresses. In the **Allowed IPs** field, enter comma-separated IP addresses or CIDR ranges, for example `10.20.30.40, 10.20.30.0/24`. Leave it blank to allow any address.

Requests from other addresses are refused with `403` and the message `Access denied. Your IP address is not allowed.` The same check applies to key-authenticated MCP connections.

This limits the value of a leaked key: for an agent that always runs from a known server or CI runner, a copy of the key does not work from any other address.

> [!TIP]
>
> Cloud CI runners often have changing addresses. If you cannot pin a range, rely on a Sending only key and keep the key out of logs instead.

***

## Make Retries Safe

When a tool call times out, the model often cannot tell whether the email went out, so agents tend to retry the send.

Both `send_email` and `send_template_email` accept an `idempotency_key`. Reuse the same value on a retry and Lettr does not send the email a second time. Without it, a retry after a timeout can send the email twice.

The key must be 1 to 255 characters, using letters, digits, periods, underscores and hyphens. Instruct the agent to derive it from the business event, not to generate a fresh one on each attempt:

```text theme={null}
When sending an order update, call send_template_email with
idempotency_key set to "order-update-<order id>-<status>".
Reuse the same key if you retry the same message.
```

The REST API has the same protection for code that calls it directly. See [Idempotency](https://docs.lettr.com/learn/sending/idempotency.md).

***

## Keep a Human in the Loop for Risky Actions

Tools that send email, overwrite data or delete it carry the MCP **destructive** annotation, including `send_email`, `send_template_email`, `cancel_scheduled_email` and `send_campaign`. Clients that support the annotation, such as Claude, can ask you to approve each call before it runs.

Check the recipients, the template and the audience in each prompt before approving it. For an unattended agent there is no prompt, so the key's permission level and a sandbox rehearsal are the controls that count.

If the agent works across several teams through OAuth, pin the team in the connection URL (`https://app.lettr.com/mcp?team=41`) so it cannot act on another one. A key is already bound to a single team.

***

## Protect the Key

A key in a client config file is a plain-text password.

* Use a separate key per agent, named for its job, so you can revoke one without affecting others.
* Keep config files that hold keys out of version control.
* Revoke a key by deleting it.
* Key-authenticated MCP calls appear in your API logs with the key's id. Filter by key name under **Logs** to see what an agent has done.

***

## A Safe Setup, End to End

For an agent that sends order updates:

**1. Rehearse on a sandbox key**

Create a sandbox key with Sending only permissions, named `order-agent-test`. Connect the agent, run the real task several times and read the emails in your own inbox (subject, body, merge data, tone). Check the **Events** page with the **Sandbox** toggle for anything unexpected.

**2. Create the live key**

Create a Sending only live key named `order-agent-prod`, with **Allowed IPs** set to the server that runs the agent.

**3. Connect the agent**

In Claude Code:

```bash theme={null}
claude mcp add --transport http lettr https://app.lettr.com/mcp \
  --header "Authorization: Bearer lttr_xxxxxxxxx"
```

**4. Set the sending rules**

Tell the agent to use saved templates and to set an `idempotency_key` on every send.

**5. Watch the first live runs**

Start with a small, low-stakes workflow and follow it in **Logs** and **Events**.

***

## Related Topics

> **[Connect with an API Key](https://docs.lettr.com/learn/mcp/api-key-auth.md)**
>
> Set up key-based MCP access and see what each key can reach

> **[API Key Permissions](https://docs.lettr.com/learn/api-keys/permissions.md)**
>
> Permission levels, scopes and IP restrictions

> **[Sandbox API Keys](https://docs.lettr.com/learn/api-keys/sandbox.md)**
>
> Test email sends without reaching real recipients

> **[Security Best Practices](https://docs.lettr.com/knowledge-base/best-practices/security.md)**
>
> Protect your API keys, webhooks, and account


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