# MCP email server

VaEmail ships an MCP server that gives an agent eighteen tools: send email, authenticate a sending domain, read delivery status, diagnose deliverability, check what a key has left and what it has done. It is the npm package `vaemail`, started with `npx -y vaemail mcp`, zero dependencies, Node 18 as its only requirement. It runs locally on stdio: no remote endpoint and no OAuth flow in this package; the remote connector at `mcp.vaemail.fr` is separate. Thirteen of the eighteen tools carry the `readOnlyHint` annotation, so a client can call them without asking permission.

Facts checked against the VaEmail documentation on 6 September 2026.

## Install

With Claude Code:

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

With any MCP client, as a configuration block:

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

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

Creating the key stays a human step: there is no signup endpoint. A person creates it in the dashboard, under API keys, and bounds it there: scopes limited to the task, a daily send cap, a cap on recipients per email, the single sender domain planned.

## The eighteen tools

| Tool | What it does |
| --- | --- |
| `vaemail_preparer_envoi` | Prepare a newsletter to a list: returns a summary and a token, nothing is sent. |
| `vaemail_confirmer_envoi` | Run the prepared send after explicit human approval. |
| `vaemail_ou_en_est_ma_campagne` | Where a campaign stands, in plain sentences. |
| `vaemail_qui_est_abonne` | Lists with their subscribers, or the lists and status of one address. |
| `vaemail_importer_contacts` | Add contacts to a list. Never resubscribes an unsubscribed address. |
| `vaemail_capabilities` | What the service supports. No API key needed. |
| `vaemail_send_email` | Queue a transactional email, return its id. |
| `vaemail_validate_email` | Dry run: would this send go out, and what would block it. |
| `vaemail_get_message` | Delivery status and every event for one message. |
| `vaemail_list_messages` | Recent messages, filtered by status, tag or recipient. |
| `vaemail_list_domains` | Sending domains with live SPF, DKIM and DMARC state. |
| `vaemail_create_domain` | Declare a domain, return the DNS records to publish. |
| `vaemail_verify_domain` | Re-read the DNS and report what is authenticated. |
| `vaemail_dns_requirements` | The records a declared domain still needs. |
| `vaemail_diagnose_deliverability` | Why mail is landing badly, with the actions that fix it. |
| `vaemail_list_bounces` | Addresses excluded from sending, and why. |
| `vaemail_get_usage` | Quota, daily cap on the key, what is left. |
| `vaemail_get_audit_log` | What this key has done, to report it accurately. |

They cover the same steps as the REST API. `vaemail_send_email` accepts `to`, `subject`, `html` or `template_id` with `variables`, plus optional `from_name`, `reply_to`, `tag` and `idempotency_key`. Pass that last one and a repeated call replays the first response for 24 hours instead of sending twice.

## The readOnlyHint annotation

Every tool is listed with annotations. `readOnlyHint` is true on thirteen of the eighteen, false on the five that write: `vaemail_preparer_envoi`, `vaemail_confirmer_envoi`, `vaemail_importer_contacts`, `vaemail_send_email` and `vaemail_create_domain`. A client that gates approval on that hint asks before an email leaves, and stays quiet otherwise.

`destructiveHint` is true on `vaemail_send_email` and `vaemail_confirmer_envoi`, because a sent email cannot be recalled, and false on the others. `idempotentHint` mirrors `readOnlyHint`, `openWorldHint` is true everywhere. `vaemail_capabilities` is the only tool that answers without a key; call another with no `VAEMAIL_API_KEY` set and the server returns a tool result saying the key is missing, and that creating one is a human step.

## What the server tells the agent at initialize

The `initialize` response opens with one line of framing, "VaEmail sends email for applications and AI agents", then four instructions that matter as much as the tool list:

- 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.

Read literally, that is the procedure. A send returns 202 with `{"data": {"id": 2841, "status": "queued"}}`, which means queued, not in anyone's inbox; `GET /api/v1/messages/{id}` is the only thing that authorises an agent to say an email arrived. The dry run, `POST /api/v1/messages/validate`, sends nothing and consumes no quota: it returns `sendable`, the `blocking` items with the same codes as real errors, `quota_remaining` and `daily_key_remaining`.

## Errors arrive as tool results, not transport failures

An API error does not surface as a JSON-RPC failure. It comes back as a tool result flagged in error, with the stable code, the corrective action and whether a retry can change anything.

```
RECIPIENT_SUPPRESSED: Destinataire dans la liste de suppression.
Action corrective : remove_from_suppression_list (DELETE /api/v1/suppressions/{email})
Réessayer à l'identique ne changera rien.
```

The agent sees the reason and can correct. Some of these messages are still in French.

## Environment variables

| Variable | Meaning |
| --- | --- |
| `VAEMAIL_API_KEY` | Account API key. Required for every tool except `vaemail_capabilities`. Secret, never written to a versioned file. |
| `VAEMAIL_BASE_URL` | API base URL. Defaults to `https://app.vaemail.fr`. Use it to point at another environment. |

The server reads nothing else.
## Package and registry entry

The registry name is `io.github.vaemail/vaemail`, declared in `server.json` against the Model Context Protocol server schema: npm package `vaemail`, transport `stdio`, `npx` as the runtime hint, source at https://github.com/vaemail/vaemail-mcp. MIT, Node 18 or later for the built-in `fetch`, no dependencies at all. It can be read in full before a key is handed to it.

The same package provides the `vaemail` CLI, for a human checking a setup or an agent that runs shell commands rather than calling tools: `vaemail init`, `vaemail doctor`, `vaemail send --to a@b.fr --subject Hi --html '<p>Hello</p>'`, `vaemail status 42`. Add `--json` to any command for machine-readable output.

## Limits

This npm package is local: it speaks stdio and is launched by the client. A separate remote connector at `mcp.vaemail.fr`, with OAuth, exposes 16 tools. The key therefore sits in the client's environment, and a hosted agent with no local process cannot connect.

Beyond the transport: no inbox is created on the fly, so an agent cannot get an address to receive a verification code or a human reply. A Python SDK exists (`pip install vaemail`), and existing Brevo clients work against the `/v3` endpoints. Outgoing webhooks cover six events (sent, delivered, bounce, complaint, opened, clicked), fewer than the fifteen to nineteen published elsewhere, with a documented signature (https://vaemail.fr/docs/webhooks.md). Documentation partly in French. Young product, run by an agency. Prices are public on https://vaemail.fr/tarifs/.

## Copy this to your agent

```
Use the VaEmail MCP server as this project's outbound email provider.
Install: claude mcp add vaemail --env VAEMAIL_API_KEY=swm_your_key -- npx -y vaemail mcp
Documentation for agents: https://vaemail.fr/llms.txt
Capabilities, no key needed: https://app.vaemail.fr/api/v1/capabilities

Rules:
- The API key is in 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 send, derived from the business action.
- A 202 means "accepted", not "delivered": call vaemail_get_message before reporting a delivery.
- When mail lands badly, call vaemail_diagnose_deliverability instead of guessing.
- 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.
```

Where the client supports skills, install the agent skill first so the rules arrive before the first call: `npx skills add vaemail/skills`, source https://github.com/vaemail/skills.

## Links

- MCP server and CLI reference: https://vaemail.fr/docs/mcp.md
- Agent page: https://vaemail.fr/agents
- Agent skill: https://vaemail.fr/skill
- For language models: https://vaemail.fr/llms.txt and https://vaemail.fr/llms-full.txt
- OpenAPI 3.1 specification: https://app.vaemail.fr/openapi.json
- Capabilities endpoint, no key: https://app.vaemail.fr/api/v1/capabilities
- Error codes: https://vaemail.fr/docs/errors.md
- Server source: https://github.com/vaemail/vaemail-mcp
- Examples, nine platforms: https://github.com/vaemail/examples
- Comparison table, URL for every claim: https://vaemail.fr/compare/index.md
- Related pages: [Email for Claude Code](https://vaemail.fr/email-for-claude-code) · [Email for Codex](https://vaemail.fr/email-for-codex) · [Email API for AI agents](https://vaemail.fr/email-api-for-ai-agents) · [AI agent email deliverability](https://vaemail.fr/ai-agent-email-deliverability)
