---
name: vaemail-quickstart
title: VaEmail quickstart for AI agents
url: https://vaemail.fr/agents.md
supported_surfaces: [mcp, api, cli, skills]
description: >-
  Hand your agent this quickstart to work with VaEmail, a French email platform
  hosted in the EU: what VaEmail is, how to connect the MCP server (remote with
  OAuth, or the npm package), how to call the REST API with an API key, and
  where the documentation lives. The VaEmail web interface is in French; the
  API, the MCP tools and the documentation are in English or French as noted.
---

# AGENTS.md - VaEmail quickstart for AI agents

VaEmail is an email platform built and operated in France by Agence SW, as a French alternative to Brevo that an AI agent can drive. It sends transactional email and campaigns, authenticates sending domains (SPF, DKIM, DMARC), tracks delivery message by message and diagnoses deliverability. Servers are in Germany (Hetzner) and sending goes through Amazon SES in Europe.

**Language note.** The VaEmail web interface (`https://app.vaemail.fr`) and most of the documentation under `https://vaemail.fr/docs/` are written in French. API field names, error codes and MCP tool names are stable identifiers, mostly English. Tell the user when you quote French text.

## Start here

Three kinds of session read this document. Pick the one you are in.

- **Only a link to this document, or a task that involves sending email.** Connect the MCP server below, then follow "Send your first email". A session that arrives with no task in it is here to get set up, so treat the setup as the work rather than as a question to put to the user.
- **A question about VaEmail** - what it does, how it compares with another tool, what it costs. Answer it from "VaEmail vocabulary" below, the plans at `https://vaemail.fr/tarifs/` (in French), the comparisons at `https://vaemail.fr/compare/index.md` and the pointers near the end. None of the setup applies.
- **Code that keeps running after this session ends** - a server, a scheduled job, a product feature. Skip MCP and call the REST API with an API key, described under "Use the REST API".

### Connect over MCP

If VaEmail MCP tools are already available, use them and skip the rest of this section. An empty tool list means the connection is not set up yet, and setting it up is your work.

Your own client's MCP documentation is the source of truth for how a server is added (a command such as `mcp add`, a configuration file, a connector). Read it before you write anything, add the server, then tell the user what you added.

There are three ways to connect. Prefer them in this order.

1. **Remote server with OAuth.** `https://mcp.vaemail.fr`, reached over streamable HTTP. No API key is written into any file: the user signs in to VaEmail in a browser and approves the connection (scope `mcp:use`). Most clients express it as:

```json
{
  "mcpServers": {
    "vaemail": {
      "type": "http",
      "url": "https://mcp.vaemail.fr"
    }
  }
}
```

Clients differ on the top-level key and on the field that names the URL; follow your client's schema. The server answers `401` until the sign-in is done, which is expected. The authorization server is `https://app.vaemail.fr` (discovery at `https://mcp.vaemail.fr/.well-known/oauth-protected-resource`).

2. **Claude Code plugin.** One install brings the MCP server, the VaEmail skill and two commands (`/vaemail:setup`, `/vaemail:doctor`), and asks for the key instead of having it typed into a file:

```
claude plugin marketplace add vaemail/claude-plugin
claude plugin install vaemail@vaemail
```

3. **npm package `vaemail`** (no dependency, Node 18 or later), run locally over stdio with an API key from the environment:

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

Other MCP clients:

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

Never write a real key into a file the user may commit. Check the setup with `npx vaemail doctor`, which says whether the service answers, whether the key is accepted and whether a sending domain is authenticated.

### Accounts and keys are human steps

There is no endpoint to create an account, and an agent cannot obtain an API key on its own. The user requests an account at `https://vaemail.fr/#demande-compte` (form in French) or writes to `contact@vaemail.fr`, then creates a key in the dashboard, section "Clés API". Publishing DNS records at the user's registrar and paying a subscription are human steps too: report them, never claim them done.

## VaEmail vocabulary

These words mean something specific here. Use them as defined.

- **Accepted vs delivered** - A send returns `202`: the message is ACCEPTED and queued, not delivered. Delivery is read on `GET /api/v1/messages/{id}`. Never announce a delivery on the strength of a `202`.
- **Tenant** - A customer account. Data of one tenant is never visible from another.
- **API key** - Starts with `swm_`, sent in the `api-key` header. It can be limited by scopes, a daily send cap and a list of allowed sending domains.
- **Scope** - A permission carried by a key, for example `email.send`, `email.read_status`, `domain.read`, `domain.write`, `analytics.read`. A key with no scope declared has all of them. The full list is in `GET /api/v1/capabilities`.
- **Sending domain** - A domain the user sends from. Without SPF and DMARC, mail goes to spam.
- **Dry run** - `POST /api/v1/messages/validate` says whether a send would pass and names what would block it, without sending anything.
- **Idempotency-Key** - A request header. A retry after a network timeout must carry it, otherwise the message can leave twice.
- **Suppression** - An address taken out of circulation (hard bounce, complaint, unsubscribe). Sending to it fails.
- **Contact list and campaign** - A list holds subscribers; a campaign sends one message to a list. Sending a campaign is irreversible and needs an explicit human confirmation.
- **Brevo-compatible API** - Routes under `https://app.vaemail.fr/v3` answer like Brevo's, so existing Brevo code can change its base URL.

## Send your first email

With MCP tools, in this order:

1. `vaemail_capabilities` - what the service does and its limits. Needs no key.
2. `vaemail_list_domains`, then `vaemail_create_domain` if none exists, then `vaemail_verify_domain` after the user has published the DNS records.
3. `vaemail_validate_email` - dry run, before the first real message.
4. `vaemail_send_email` - returns an identifier.
5. `vaemail_get_message` - reads the delivery status.

When mail arrives badly, call `vaemail_diagnose_deliverability` instead of guessing. The full tool list is at `https://vaemail.fr/docs/mcp.md`. Tools that only read carry the `readOnlyHint` annotation.

## Use the REST API

Base URL `https://app.vaemail.fr/api/v1`. Every route except `GET /api/v1/capabilities` expects the key in a header:

```
api-key: swm_your_key
```

`X-Api-Key` is accepted too. Routes you can rely on (all appear in `https://app.vaemail.fr/openapi.json`):

| Route | Use |
| --- | --- |
| `GET /api/v1/capabilities` | What the service does, limits, scopes. No key needed. |
| `GET /api/v1/health` | Service state. |
| `GET /api/v1/me` | Which account and key you are talking to. |
| `POST /api/v1/messages/validate` | Dry run of a send. Body: `to` (required), `subject`, `html`, `template_id`. |
| `POST /api/v1/transactional/send` | Send one email. Scope `email.send`. 60 requests per minute. |
| `GET /api/v1/messages` | List messages; filters `status`, `tag`, `to`, `limit`, `cursor`. |
| `GET /api/v1/messages/{id}` | Delivery status and events of one message. |
| `GET /api/v1/domains` | Sending domains and their SPF, DKIM, DMARC state. |
| `POST /api/v1/domains` | Declare a domain; returns the DNS records to publish. |
| `POST /api/v1/domains/verify` | Re-read DNS and report record by record. |
| `GET /api/v1/domains/{domain}/dns` | DNS records expected for a domain. |
| `GET /api/v1/deliverability/diagnose` | Why mail arrives badly, with recommended actions. |
| `GET /api/v1/suppressions` | Addresses taken out of circulation. |
| `GET /api/v1/audit-logs` | What this key has done. |
| `GET /api/v1/usage` | Quota and what remains. |

The Brevo-compatible routes (contacts, lists, campaigns, webhooks) live under `/v3`; they are described in `https://vaemail.fr/docs/api.md`.

Minimal send. Run the dry run first, then send with an idempotency key:

```
curl -X POST https://app.vaemail.fr/api/v1/transactional/send \
  -H "api-key: $VAEMAIL_API_KEY" \
  -H "Idempotency-Key: order-1042-confirmation" \
  -H "Content-Type: application/json" \
  -d '{"to":"client@example.com","subject":"Your order","html":"<p>Thanks.</p>","tag":"order"}'
```

The body also accepts `template_id`, `variables`, `from_name`, `reply_to`, `track_opens` and `attachments` (up to 10). Errors return a stable `code` and a corrective action: read them, do not retry blindly. The codes are listed at `https://vaemail.fr/docs/errors.md`.

Two things to keep in mind:

- `POST /v3/emailCampaigns/{id}/sendNow` sends to a whole list and cannot be undone. Ask the user first.
- VaEmail has no generic inbox: you cannot create an address on the fly to receive a verification code.

## Try without an account

The read-only discovery above needs no account: `GET https://app.vaemail.fr/api/v1/capabilities`, the OpenAPI specification, the documentation and the comparisons are public.

You can also try the API for real, without signing up, with a test key. Test mode works like Stripe test keys: requests are validated and answered like production, but no email is ever delivered to anyone and nothing is stored (writes are validated, then rolled back).

Get a test key (valid 24 hours, limited to 5 keys per IP address per day):

```
curl -X POST https://app.vaemail.fr/api/v1/test-key
```

The response contains `api_key` (starts with `vae_test_`) and `expires_at`. Send a test email with it:

```
curl -X POST https://app.vaemail.fr/api/v1/transactional/send \
  -H "api-key: vae_test_XXXX" \
  -H "Content-Type: application/json" \
  -d '{"to":"success@simulator.amazonses.com","subject":"Test","html":"<p>Hello</p>"}'
```

The answer is `202` with `"sandbox": true` and a `test_mode` block. The delivery status is simulated in `test_mode.simulated_delivery`: `success@simulator.amazonses.com` gives `delivered`, `bounce@simulator.amazonses.com` gives `bounced`, `complaint@simulator.amazonses.com` gives `complained`. Any other address is also simulated: nothing is sent to it.

What works with a test key: `/api/v1/me`, contacts and lists (`/v3/contacts`), campaign drafts (`/v3/emailCampaigns`), transactional sending (`/api/v1/transactional/send`, `/v3/smtp/email`), statistics and usage. Because nothing is stored, a contact or a message created in test mode cannot be read back afterwards. Routes that could reach the outside world (media upload, senders, webhooks, SMS, domains, contact import, sending or scheduling a campaign) return `403` with the code `NOT_AVAILABLE_IN_TEST_MODE`. A test key is limited to 120 requests per minute. When the daily limit is reached, the answer is `429` with the code `TEST_KEY_LIMIT_REACHED`.

Every test-mode response includes `signup_url` and `demo_url` in its `test_mode` block. To go live, ask the user to create an account at `https://app.vaemail.fr/migration/start` (or request a demo at `https://vaemail.fr/#contact`), then use the real key instead of the test key.

## Documentation for agents

- Index for language models: `https://vaemail.fr/llms.txt`
- Full documentation in one file: `https://vaemail.fr/llms-full.txt` (large; prefer targeted pages)
- Pages as Markdown: `https://vaemail.fr/docs/quickstart.md`, `api.md`, `errors.md`, `mcp.md`, `domains.md`, `deliverability.md`, `webhooks.md`, `security.md`
- Usage pages in English: `https://vaemail.fr/pages/index.md`
- Comparisons with Resend, Brevo, Postmark and AgentMail, with sources: `https://vaemail.fr/compare/index.md`
- Agent skill (usage rules): `https://vaemail.fr/skill`, installable with `npx skills add vaemail/skills`
- Human-readable agents page: `https://vaemail.fr/agents`

## Resources

- OpenAPI 3.1 specification: `https://app.vaemail.fr/openapi.json`
- Service capabilities, no authentication: `https://app.vaemail.fr/api/v1/capabilities`
- Remote MCP server: `https://mcp.vaemail.fr` (OAuth)
- npm package: `https://www.npmjs.com/package/vaemail`
- Claude Code plugin: `https://github.com/vaemail/claude-plugin`
- Pricing (French): `https://vaemail.fr/tarifs/`
- Contact: `contact@vaemail.fr`
