DOCS

e2a developer docs

e2a is the open-source email API for applications and AI agents. Any product can send transactional email over HTTP or an SDK; agent-native systems can also receive through real two-way inboxes over MCP, a signed webhook, a WebSocket stream, or REST. Inbound mail includes structured SPF, DKIM, and DMARC evidence that applies to the From domain, not a person or mailbox. These pages cover how to connect, authenticate API calls, and work with email threads; the exhaustive endpoint reference is the API reference.

Where the reference lives

Each document below is a plain, fetchable file — the Markdown ones are written to be read by an agent as easily as by a person.

  • API reference Every /v1 endpoint, request and response body, enum, and error code, rendered from the live OpenAPI contract.
  • openapi.yaml The OpenAPI 3.1 document itself — generated from the handlers and authoritative for exact signatures.
  • setup.md Connect a client, pick or create an inbox, and confirm it is ready to send and receive.
  • auth.md The credential model in full: OAuth 2.1 with Dynamic Client Registration, API key scopes, errors, and revocation.
  • sdk.md TypeScript and Python quick starts — send, receive over webhook or WebSocket, reply in-thread — plus raw REST.
  • templates.md Email templates (beta): reusable server-rendered bodies with {{variable}} interpolation and a starter catalog.
  • llms.txt Machine-readable index of everything above. llms-full.txt inlines the whole corpus in one fetch.

Frequently asked questions

How do I connect an AI agent to e2a — over MCP, REST, or an SDK?

e2a offers all three over one API, so the choice is about how your agent runs rather than what it can do. Point any Streamable HTTP MCP client at https://api.e2a.dev/mcp and the agent gets the inbox as tools with no API key to paste — the fastest path for coding agents and agent frameworks. If you are writing the integration yourself, install @e2a/sdk for TypeScript or e2a for Python to get typed clients with one-call webhook verification and a WebSocket listen() stream; if your language has no SDK, call the REST API at https://api.e2a.dev/v1 directly against the published OpenAPI 3.1 contract.

How does authentication work for the e2a API?

Every authenticated e2a request carries an Authorization: Bearer credential, and e2a accepts two kinds, told apart by prefix. Interactive MCP clients use OAuth 2.1 access tokens (ate2a_…), obtained by self-registering through RFC 7591 Dynamic Client Registration with PKCE, so no human ever pastes a secret. API keys are issued from the e2a dashboard or CLI in two scopes — an account key (e2a_acct_…) manages agents, domains, and keys, while an agent key (e2a_agt_…) is pinned to a single inbox — and are what you use for servers, scripts, and CI where no browser is available.

Should my agent receive email over a webhook or a WebSocket?

Use a webhook when the agent runs as a service that can host a public HTTPS endpoint: e2a POSTs a signed metadata trigger, and the SDK's constructEvent or construct_event helper verifies the per-webhook HMAC before you hydrate the full message. Use the WebSocket stream — client.listen(agentEmail) in either SDK, or e2a listen in the CLI — when the agent runs on a laptop or behind a firewall and cannot host a URL at all. Both carry the same email.received event, and REST polling and the MCP tools read the same mailbox, so different deployments of the same agent can use different channels.

How does e2a thread an email conversation?

Reply with e2a's reply operation and the original message_id — client.messages.reply(...) in the SDKs, reply_to_message over MCP — and e2a sets the standards-compliant reply headers that keep the exchange in one thread in Gmail and Outlook. conversation_id is a separate, caller-owned correlation field: bind it to your agent framework's session ID so the agent has memory across replies, but on its own it does not set those headers and it is never an authorization decision. Starting a fresh send instead of a reply opens a new thread in the recipient's mail client.

How do I keep a retried API call from sending the same email twice?

e2a's send, reply, and forward operations accept an Idempotency-Key header — use one UUIDv4 per logical message. Reuse the same key on transport retries such as timeouts and dropped connections and e2a replays the original response instead of sending again; reusing a key with a different body returns 422, and a genuinely new message needs a fresh key. Separately, a send that returns 202 with status pending_review has already been accepted and is being held for approval, so report the status and stop rather than retrying, which would queue a duplicate.

Is the e2a /v1 API stable enough to build on?

e2a's core /v1 REST API and its TypeScript and Python SDKs are generally available: v1.5.0 is the compatibility baseline, there are no breaking changes within /v1, and every later release is audited against that tag. A small, explicitly enumerated set of newer resources is still beta and may change — those are marked x-stability-level: beta in the OpenAPI document and (beta) in the docs, so GA and beta can be told apart mechanically rather than by reading prose. The contract at https://e2a.dev/v1/openapi.yaml is generated from the live handlers and drift-checked in CI, so it cannot fall out of step with the running service.

Give your agent an inbox

Free tier, no card. Create an inbox on the shared domain and send your first message without any DNS setup.

Start building