# Developer quickstart

A REST API and an MCP server for sending, receiving, reading threads, and managing domains and mailboxes. Both run on your own server.

**Invite-only beta.** During the beta we set up your server with you and give you an onboarding brief with your API address and a scoped token. The examples below assume you have both. [Get a beta invite](https://emailplane.com/invite/)

## Start with your coding agent

Paste this into Claude Code, Codex, Cursor or any coding agent working in your app's repository:

```text
Add email to this app with eMailPlane.
Read https://emailplane.com/llms-full.txt before writing code.
The API address is in the EMAILPLANE_API environment variable and the token
is in EMAILPLANE_TOKEN. Never print, log or commit the token.

1. Call GET $EMAILPLANE_API/v1/tokens/self and show me the token's scopes.
2. Add one sendEmail() helper that POSTs to /v1/emails and sends an
   Idempotency-Key derived from the business event (for example the order id),
   so retries never send twice.
3. Before sending to a list, call POST /v1/sends/preflight and respect its answer.
4. Read replies with GET /v1/inbound, paging with next_cursor.
5. Handle errors from the { "error": { "code", "message" } } envelope.
Ask me before sending to any address that isn't mine.
```

One-prompt install on your own server, run by your coding agent, is (coming soon).

## API basics

Your apps call the API on your own server. It is never exposed to the public internet, and every request carries a bearer token with only the scopes it needs.

| Call | What it does |
|---|---|
| `GET /v1/tokens/self` | Who am I: the token's scopes, quota and usage |
| `POST /v1/emails` | Send an email. Returns `202` with `id`, `message_id` and `state` |
| `POST /v1/sends/preflight` | Ask whether a send would be accepted, where it would stop and how much headroom is left, without sending |
| `GET /v1/emails/:id` | The state of one message |
| `GET /v1/events` | Delivery events for your service (accepted, delivered, deferred, bounced, complained), filterable |
| `GET /v1/inbound` | Mail your service received, newest first, with `next_cursor` paging |
| `GET /v1/inbound/threads` | Received mail grouped into conversations |
| `GET /v1/inbound/threads/:id` | One conversation, every message in order |
| `POST /v1/webhooks` | Register a URL that gets a signed `message.received` event when a reply arrives |
| `POST /v1/mail-domains` | Add a domain; `POST /v1/mail-domains/:id/verify` checks its DNS |
| `POST /v1/mailboxes` | Create a mailbox a person can use in any mail app |
| `GET /v1/templates` | Versioned templates you can render and promote |

### Send an email

```bash
curl -sS "$EMAILPLANE_API/v1/emails" \
  -H "Authorization: Bearer $EMAILPLANE_TOKEN" \
  -H "Idempotency-Key: order-1042-shipped" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "orders@yourapp.com",
    "to": ["customer@example.com"],
    "subject": "Your order has shipped",
    "text": "It is on the way."
  }'
```

`202 Accepted` means the message is safely queued, not yet delivered. Follow it with `GET /v1/emails/:id` or `GET /v1/events`. Sending the same `Idempotency-Key` again returns the first answer instead of sending twice.

### Errors

Every error has the same shape, with a machine-readable code and, where it helps, the field that caused it. Errors never repeat an email address back to you, so they are safe to paste into a bug report or an agent transcript.

```json
{ "error": { "code": "request.invalid", "message": "...", "field": "cursor" } }
```

## MCP

The eMailPlane MCP server gives an agent 41 tools over the same API and the same token scopes: sending, preflight, reading inbound mail and threads, waiting for a reply, templates, domains, mailboxes and API keys. [MCP setup](https://emailplane.com/developers/mcp/)

## Status

| Capability | Status |
|---|---|
| Send API with idempotency keys, preflight, suppression and delivery events | (in private beta) |
| Receive mail and read it as threads through the API | (in private beta) |
| Domains, mailboxes for people, and IMAP login from any mail app | (in private beta) |
| Virus scanning of inbound mail on your server | (in private beta) |
| MCP server (41 tools) | (in private beta) |
| Reply to a message in its thread (`in_reply_to`) | (in private beta) |
| Signed webhooks when mail arrives (`message.received`, message and thread ids only) | (in private beta) |
| `wait_for_reply`: wait up to 50 seconds for the answer in one call, and call again to keep waiting | (in private beta) |
| Remote MCP endpoint at `https://mail.<your-domain>/mcp` | (coming soon) |
| Separate addresses and keys for each agent | (coming soon) |
| Sender trust labels and untrusted-content wrapping for agents | (coming soon) |
| Drafts and approval policies (approve by reply or passkey) | (coming soon) |
| An event stream | (coming soon) |
| `npx emailplane` CLI and a local sandbox | (coming soon) |
| OpenAPI description | (coming soon) |

## Machine-readable versions

This site publishes [/llms.txt](https://emailplane.com/llms.txt), a full-text [/llms-full.txt](https://emailplane.com/llms-full.txt), and a Markdown version of every page: add `index.html.md` to any page's address, for example [/pricing/index.html.md](https://emailplane.com/pricing/index.html.md).

---

Source: https://emailplane.com/developers/
