From 52eb1405cfb3a083909bd0ad4ee4177bfa6cadd6 Mon Sep 17 00:00:00 2001 From: Josh Zhang <39790535+jiashuoz@users.noreply.github.com> Date: Mon, 18 May 2026 16:28:39 -0700 Subject: [PATCH] Add e2a integration (#1766) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add e2a integration e2a is an authenticated email gateway for AI agents — SPF/DKIM-verified inbound, optional human-in-the-loop approval before outbound mail ships. Distributed as an MCP stdio server via npx -y @e2a/mcp-server, exposing 11 tools for inbox management, threaded replies, and HITL approval flows. Source: https://github.com/Mnexa-AI/e2a/tree/main/mcp npm: https://www.npmjs.com/package/@e2a/mcp-server * docs(e2a): shorten catalog_description per review feedback --- docs/integrations/assets/e2a.png | Bin 0 -> 11711 bytes docs/integrations/e2a.md | 177 +++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+) create mode 100644 docs/integrations/assets/e2a.png create mode 100644 docs/integrations/e2a.md diff --git a/docs/integrations/assets/e2a.png b/docs/integrations/assets/e2a.png new file mode 100644 index 0000000000000000000000000000000000000000..f8fad9b3e6be279cfd8ed3f1417882b11a8fa659 GIT binary patch literal 11711 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 literal 0 HcmV?d00001 diff --git a/docs/integrations/e2a.md b/docs/integrations/e2a.md new file mode 100644 index 0000000000..2d79f83438 --- /dev/null +++ b/docs/integrations/e2a.md @@ -0,0 +1,177 @@ +--- +catalog_title: e2a +catalog_description: Authenticated email gateway for AI agents with human-in-the-loop approval +catalog_icon: /integrations/assets/e2a.png +catalog_tags: ["mcp"] +--- + +# e2a MCP tool for ADK + +
+ Supported in ADKPythonTypeScript +
+ +The [e2a MCP Server](https://github.com/Mnexa-AI/e2a/tree/main/mcp) connects +your ADK agent to [e2a](https://e2a.dev), an authenticated email gateway +built for AI agents. Inbound mail is SPF/DKIM-verified before it reaches +your agent. Outbound mail can be held for human approval before it ships. + +## Use cases + +- **Give agents their own inboxes**: Provision dedicated email addresses + (e.g. `support-bot@your-domain.com`) and let agents send and receive + mail just like a teammate. + +- **Authenticated inbound**: Every incoming message arrives with SPF and + DKIM verification results so your agent knows whether the sender is who + they claim to be. + +- **Human-in-the-loop approval**: Configure HITL on any agent and + outbound messages are held in a pending queue until a reviewer + approves them — optionally with edits to subject, body, or recipients + before sending. + +- **Automate threaded conversations**: Reply to received emails with + proper In-Reply-To and References headers preserved, so threads stay + intact across multiple turns. + +## Prerequisites + +- A free [e2a account](https://e2a.dev) and an API key from the dashboard. +- Node.js 18+ on the machine running the agent (the MCP server is + distributed via `npx -y @e2a/mcp-server`). + +## Use with agent + +=== "Python" + + === "Local MCP Server" + + ```python + from google.adk.agents import Agent + from google.adk.tools.mcp_tool import McpToolset + from google.adk.tools.mcp_tool.mcp_session_manager import StdioConnectionParams + from mcp import StdioServerParameters + + E2A_API_KEY = "YOUR_E2A_API_KEY" + E2A_AGENT_EMAIL = "your-bot@your-domain.com" # optional default inbox + + root_agent = Agent( + model="gemini-flash-latest", + name="e2a_agent", + instruction=( + "You manage email through the e2a tools. Call whoami once " + "to find your inbox address. Use list_messages and " + "get_message to read; use reply_to_message (not " + "send_email) when replying to an existing thread so " + "threading headers are preserved." + ), + tools=[ + McpToolset( + connection_params=StdioConnectionParams( + server_params=StdioServerParameters( + command="npx", + args=["-y", "@e2a/mcp-server"], + env={ + "E2A_API_KEY": E2A_API_KEY, + "E2A_AGENT_EMAIL": E2A_AGENT_EMAIL, + }, + ), + timeout=30, + ), + ) + ], + ) + ``` + +=== "TypeScript" + + === "Local MCP Server" + + ```typescript + import { LlmAgent, MCPToolset } from "@google/adk"; + + const E2A_API_KEY = "YOUR_E2A_API_KEY"; + const E2A_AGENT_EMAIL = "your-bot@your-domain.com"; // optional default inbox + + const rootAgent = new LlmAgent({ + model: "gemini-flash-latest", + name: "e2a_agent", + instruction: + "You manage email through the e2a tools. Call whoami once " + + "to find your inbox address. Use list_messages and " + + "get_message to read; use reply_to_message (not " + + "send_email) when replying to an existing thread so " + + "threading headers are preserved.", + tools: [ + new MCPToolset({ + type: "StdioConnectionParams", + serverParams: { + command: "npx", + args: ["-y", "@e2a/mcp-server"], + env: { + E2A_API_KEY: E2A_API_KEY, + E2A_AGENT_EMAIL: E2A_AGENT_EMAIL, + }, + }, + }), + ], + }); + + export { rootAgent }; + ``` + +## Available tools + +### Identity + +Tool | Description +---- | ----------- +`whoami` | Return the default agent's full record (requires `E2A_AGENT_EMAIL`) +`list_agents` | List every agent inbox owned by the authenticated user +`create_agent` | Register a new inbox using a slug on the shared domain; defaults to `local` mode so the agent receives mail by polling — no webhook required + +!!! warning "Cloud-mode agents must verify webhook signatures" + + When you create an agent with `agent_mode: "cloud"`, e2a HMAC-signs every + webhook delivery against your account's webhook signing secret + (`E2A_WEBHOOK_SECRET`, shown in the [e2a dashboard](https://e2a.dev)). + Your webhook handler must verify the signature on every request — + the e2a SDK exposes `parseWebhook(body, secret)` which parses and + verifies in one call. Local-mode agents (the default) avoid this + entirely by polling via `list_messages`. A complete runnable + cloud-mode + ADK example with proper signature verification lives + at [github.com/Mnexa-AI/e2a/tree/main/examples/adk-cloud-webhook](https://github.com/Mnexa-AI/e2a/tree/main/examples/adk-cloud-webhook). + +### Messages + +Tool | Description +---- | ----------- +`send_email` | Send a new email; returns `status: pending_approval` instead of `sent` when HITL is enabled +`reply_to_message` | Reply to an inbound message; preserves In-Reply-To and References headers +`list_messages` | List inbound mail with `status` filter (unread / read / all) and pagination +`get_message` | Fetch full body, headers, and attachment metadata for one message + +### Human-in-the-loop approval + +Tool | Description +---- | ----------- +`list_pending_messages` | List outbound mail awaiting human approval, soonest-expiring first +`get_pending_message` | Get the full draft (subject, recipients, body) of a pending message +`approve_pending_message` | Send a held message, optionally with reviewer edits (subject / body / recipients) +`reject_pending_message` | Discard a held message; optional `reason` stored for audit + +## Configuration + +Variable | Required | Default | Description +-------- | -------- | ------- | ----------- +`E2A_API_KEY` | Yes | — | Your e2a API key +`E2A_AGENT_EMAIL` | No | — | Default agent inbox; scopes tools so the LLM doesn't repeat the address on every call +`E2A_BASE_URL` | No | `https://e2a.dev` | Self-hosted deployment URL + +## Additional resources + +- [e2a MCP Server source](https://github.com/Mnexa-AI/e2a/tree/main/mcp) +- [Runnable ADK example](https://github.com/Mnexa-AI/e2a/tree/main/mcp/examples/adk) +- [e2a documentation](https://e2a.dev) +- [npm package](https://www.npmjs.com/package/@e2a/mcp-server)