# Email for Claude Code

VaEmail gives Claude Code outbound email through a local MCP server: the npm package `vaemail`, eighteen tools, zero dependencies. One command wires it in, an agent skill gives the agent the rules before its first call, and the API key can be scoped and capped so a retrying program cannot send more than it should. A send returns 202, which means accepted, not delivered; the outcome is read on `GET /api/v1/messages/{id}`.

Facts checked against the VaEmail documentation on 6 September 2026.

## Install the MCP server

```bash
export VAEMAIL_API_KEY=swm_your_key
claude mcp add vaemail --env VAEMAIL_API_KEY=$VAEMAIL_API_KEY -- npx -y vaemail mcp
```

The server runs on stdio. It reads two environment variables: `VAEMAIL_API_KEY`, required for every tool except `vaemail_capabilities`, and `VAEMAIL_BASE_URL`, which defaults to `https://app.vaemail.fr`. The registry entry is `io.github.vaemail/vaemail`, source at https://github.com/vaemail/vaemail-mcp.

Getting the key is a human step: no signup endpoint exists, a person creates it in the VaEmail dashboard under API keys, and it is shown once. Ask for it as an environment variable, not pasted into a chat.

`npx vaemail init` then reports, in order, whether the service responds, whether the key is accepted, and whether a sending domain is authenticated. It also prints the MCP configuration block.

## The .mcp.json alternative

Claude Code reads a project-level `.mcp.json` at startup. The version shipped in `examples/claude-code` expands the variable instead of holding the key:

```json
{
  "mcpServers": {
    "vaemail": {
      "command": "npx",
      "args": ["-y", "vaemail", "mcp"],
      "env": { "VAEMAIL_API_KEY": "${VAEMAIL_API_KEY}" }
    }
  }
}
```

Save the block above as `.mcp.json` at the root of your project, then:

```bash
export VAEMAIL_API_KEY=swm_your_key   # never commit it
cd /path/to/your/project && claude
```

## Install the skill

```bash
npx skills add vaemail/skills
```

Source: https://github.com/vaemail/skills, readable at https://vaemail.fr/skill. It covers the setup order, domain authentication, the dry run, idempotent sending, delivery tracking, every error code with its corrective action, the operations that require a human, and how to bound a key. Installed before the first call, the agent starts with the rules, not just with a tool list.

## First send through the MCP tools

Run them in this order the first time, and again whenever the configuration changed.

0. Authenticate the sending domain. `vaemail_create_domain` returns the DNS records to publish, each with its role. A record marked `publishable: false` still contains a placeholder: report it, do not publish it. Publishing the records at the registrar is a human step. After propagation, `vaemail_verify_domain` gives the verdict per record: SPF, DKIM, DMARC. Sending before this returns `DOMAIN_NOT_VERIFIED`.
1. `vaemail_validate_email`. A dry run that sends nothing and consumes no quota. The response says `sendable`, lists `blocking` items using the same codes as real errors, and returns `quota_remaining` and `daily_key_remaining`. If `sendable` is false, fix what blocks and do not send.
2. `vaemail_send_email`. Arguments: `to`, `subject`, `html` or `template_id` with `variables`, plus optional `from_name`, `reply_to` and `tag`. Always pass `idempotency_key`, derived from the business action, for example `order-8812-confirmation`: a retry after a network timeout then replays the first response instead of sending again. One recipient per call. Scope `email.send`. Rate limit 60 requests per minute.
3. Read the answer correctly. A 202 means the message is accepted, not delivered, and not in anyone's inbox. The accepted status is `queued` or `held`:

```json
{ "success": true, "data": { "id": 2841, "status": "queued" } }
```

The same sequence over REST, dry run first:

```bash
curl -X POST https://app.vaemail.fr/api/v1/messages/validate \
  -H "api-key: $VAEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to":"recipient@example.com","html":"<p>Hello, your invoice is attached.</p>"}'

curl -X POST https://app.vaemail.fr/api/v1/transactional/send \
  -H "api-key: $VAEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: invoice-2412" \
  -d '{"to":"recipient@example.com","subject":"Your invoice","html":"<p>Hello, your invoice is attached.</p>"}'
```

The `Idempotency-Key` header memorises the response for 24 hours and replays it identically, with `Idempotent-Replay: true`, so a retry after a network timeout does not send a second message. The same key with a different body is refused with `409 IDEMPOTENCY_KEY_REUSED`, which is a bug in the key derivation rather than a replay. Server errors are not memorised, so a 5xx can be retried with the same key.

## Reading delivery

`vaemail_get_message`, or `GET /api/v1/messages/{id}` with scope `email.read_status`. The `status` field is one of `queued`, `sent`, `delivered`, `failed`, `suppressed`, `held`, `cancelled`. On failure, `error` carries the reason returned by the transport and `events` the sequence of what happened. Only `delivered` allows the agent to say the email arrived. Poll a few times with a pause of a few seconds: confirmation depends on the recipient's provider.

When mail from a domain lands badly, `vaemail_diagnose_deliverability` returns SPF, DKIM and DMARC verdicts, the problems found and the actions that fix them. More on that in [AI agent email deliverability](https://vaemail.fr/ai-agent-email-deliverability).

A DNS record returned with `publishable: false` still misses a value named in `missing_values`. Report it and wait: publishing it as it stands breaks the domain's authentication without any error surfacing.

## What the server tells the agent at startup

The server returns these instructions in its `initialize` response; the tools arrive on `tools/list`:

```
VaEmail sends email for applications and AI agents. A send is accepted, not
delivered: check vaemail_get_message for the outcome. Before the first real send,
run vaemail_validate_email. When mail lands badly, run
vaemail_diagnose_deliverability rather than guessing. Publishing DNS records and
paying for a plan are human steps: report them, never claim them done.
```

An API error does not surface as a transport failure but as a tool result marked in error, carrying the stable code, whether it is retryable, and the corrective action, with the endpoint that performs it when there is one.

## Which tools are read-only

Thirteen of the eighteen tools are annotated `readOnlyHint: true`; the five that are not are `vaemail_preparer_envoi`, `vaemail_confirmer_envoi`, `vaemail_importer_contacts`, `vaemail_send_email` and `vaemail_create_domain`. An MCP client can therefore tell what it may call freely from what engages something outside.

## Guardrails through a scoped key

Ask for a key created for this agent, named after it, and bounded at creation:

- scopes: `email.send` and `email.read_status` are enough to send and track; add `billing.read` to read what quota is left, `analytics.read` to read the audit log, and `domain.read` plus `domain.write` only if the agent configures the domain. Eight scopes exist in total. A call outside them returns 403 `INSUFFICIENT_SCOPE`, naming the missing scope and the ones the key holds.
- `max_emails_per_day`: the volume the agent is supposed to produce. Beyond it, 429 `DAILY_LIMIT_REACHED`, marked retryable since the cap resets.
- `max_recipients_per_email`: 1 for transactional mail.
- `allowed_domains`: the single planned sender domain. Sending from another one returns 403 `SENDER_DOMAIN_NOT_ALLOWED`.

Before a batch, `GET /api/v1/usage` (scope `billing.read`) returns the monthly quota, today's sends, and for the current key its scopes, daily cap and what remains. `GET /api/v1/audit-logs` (scope `analytics.read`) returns one line per call: which key, which operation, which parameters, which result, how many emails were engaged. Message bodies and attachments never appear there.

## What Claude Code cannot do with VaEmail

No inbox is created on demand, so an agent cannot get an address to receive a verification code or a human reply. Inbound exists only for prospecting sequences attached to a declared IMAP mailbox. There is a Python SDK (`pip install vaemail`); existing Brevo clients work against the `/v3` endpoints. The npm MCP server runs on stdio. A separate remote connector at `mcp.vaemail.fr`, with OAuth, exposes 16 tools. Six webhook events are exposed: sent, delivered, bounce, complaint, opened, clicked. The documentation is partly in French, and the product is young, run by an agency rather than a funded company. Prices are public on https://vaemail.fr/tarifs/.

Publishing DNS records, creating the account or the key, paying, raising a quota, removing an address from the suppression list and sending a campaign to a whole list are human steps. `POST /v3/emailCampaigns/{id}/sendNow` is irreversible and requires an explicit confirmation in the request body.

## Copy this to your agent

```
Integrate VaEmail into this project as the outbound email provider.

Official documentation for agents: https://vaemail.fr/llms.txt
OpenAPI specification: https://app.vaemail.fr/openapi.json
What the service supports, no key needed: https://app.vaemail.fr/api/v1/capabilities

Rules:
- The API key is in the environment variable VAEMAIL_API_KEY. Do not ask for it, never
  write it to a versioned file.
- Before any real send, call vaemail_validate_email and stop if "sendable" is false.
- Pass idempotency_key on every vaemail_send_email call, derived from the business action.
- A send is accepted, not delivered: call vaemail_get_message before you report a
  delivery.
- Without the MCP server, the same steps are POST /api/v1/messages/validate, POST
  /api/v1/transactional/send with an Idempotency-Key header, and GET
  /api/v1/messages/{id}.
- Publishing DNS records, creating an account or paying are human steps: name them, never
  declare them done.

Start with `npx vaemail init` and tell me what it reports.
```

## Links

- Agent page: https://vaemail.fr/agents
- MCP server and CLI: https://vaemail.fr/docs/mcp.md
- Error codes: https://vaemail.fr/docs/errors.md
- Scopes, caps and audit log: https://vaemail.fr/docs/security.md
- Index for language models: https://vaemail.fr/llms.txt
- Full documentation in one file: https://vaemail.fr/llms-full.txt
- OpenAPI 3.1: https://app.vaemail.fr/openapi.json
- Capabilities, no key: https://app.vaemail.fr/api/v1/capabilities
- Runnable examples: https://github.com/vaemail/examples
- Comparison with Resend, Brevo, Postmark, AgentMail: https://vaemail.fr/compare/index.md
- Related pages: [MCP email server](https://vaemail.fr/mcp-email-server) · [Email API for AI agents](https://vaemail.fr/email-api-for-ai-agents) · [Email for Codex](https://vaemail.fr/email-for-codex)
