AgentMail

AgentMail

Build email-native agent workflows with AgentMail

Build email-native agent workflows with AgentMail

Jun 3, 20265 min readBy AgentMail Blog

Autonomous agents need to send, receive, and search real emails as part of production workflows, but most agent frameworks lack native email capabilities. AgentMail provides an Email Inbox API that gives AI agents real email functionality via REST API and TypeScript SDK. Integrate AgentMail inbox creation, sending, and message listing directly into your agent's action tools to enable email-first workflows. Use webhooks and reply threads to build multi-turn email conversations where agents collaborate with humans and external systems seamlessly.

What this tutorial covers

  • Outcome: You can deploy a production-grade agent workflow that creates dedicated email inboxes, sends messages, receives replies, and maintains conversation threads—all via AgentMail's typed SDK.
  • Endpoints used: `POST /inboxes`, `POST /inboxes/{inbox_id}/messages/send`, `POST /webhooks`
  • SDK methods: `client.inboxes.create(opts?: { username?: string; domain?: string; displayName?: string; metadata?: object }): Promise`, `client.inboxes.messages.send(inboxId: string, opts: { to: string; subject: string; text: string }): Promise`, `client.inboxes.messages.list(inboxId: string, opts?: { limit?: number, pageToken?: string, labels?: string[] }): Promise`, `client.inboxes.messages.reply(inboxId: string, messageId: string, opts: { text: string, html?: string, attachments?: object[], reply_all?: boolean }): Promise`, `client.inboxes.threads.list(inboxId: string, opts?: { limit?: number, pageToken?: string, labels?: string[], before?: string, after?: string, ascending?: boolean }): Promise`
  • Language: typescript
  • Auth: API key (X-API-Key header) or Bearer token
  • Estimated implementation time: ~18 minutes

Step 1: Initialize AgentMail client and authenticate

Set up the AgentMail TypeScript SDK with authentication so your agent can make inbox and message calls. Use API key authentication to establish a secure client connection for all downstream operations.

Client initialization

typescript
1import { AgentMailClient } from "agentmail";
2import "dotenv/config";
3
4async function initializeAgentMail() {
5  const client = new AgentMailClient({
6    apiKey: process.env.AGENTMAIL_API_KEY,
7  });
8  console.log("AgentMail client initialized successfully");
9  return client;
10}
11
12const client = await initializeAgentMail();

The client is ready to create inboxes, send messages, and list threads without additional authentication headers.

Step 2: Create a dedicated inbox for your agent

AgentMail's create inbox endpoint provisions a real, usable email address for your agent with optional display name and metadata. Store the returned inbox_id so your agent can send and receive messages from this identity throughout its workflow.

Provision agent inbox

typescript
1import { AgentMailClient } from "agentmail";
2import "dotenv/config";
3
4async function createAgentInbox() {
5  const client = new AgentMailClient({
6    apiKey: process.env.AGENTMAIL_API_KEY,
7  });
8
9  const inbox = await client.inboxes.create({
10    username: "my-agent",
11    displayName: "Support Agent",
12    metadata: {
13      agent_type: "support",
14      active: true,
15    },
16  });
17
18  const inboxId = inbox.id;
19  console.log(`Agent inbox created with ID: ${inboxId}`);
20  return inboxId;
21}
22
23createAgentInbox().catch(console.error);

Response:

json
1{
2  "type": "message.received",
3  "message": {
4    "message_id": "<abc123@agentmail.to>",
5    "inbox_id": "auto-reply@agentmail.to",
6    "from_": "John Doe <john@example.com>",
7    "subject": "Hello",
8    "text": "Email body content..."
9  }
10}

Step 3: Send an email from the agent's inbox

Use AgentMail's send method to dispatch an email from your agent's inbox to external stakeholders or internal systems. The send call returns confirmation, allowing your agent to log or track outbound communication as part of its execution trace.

Send outbound message

typescript
1import { AgentMailClient } from "agentmail";
2import "dotenv/config";
3
4async function sendEmailFromAgentInbox() {
5  const client = new AgentMailClient({
6    apiKey: process.env.AGENTMAIL_API_KEY,
7  });
8
9  const inboxId = "your-agent-inbox@agentmail.to";
10  const confirmation = await client.inboxes.messages.send(inboxId, {
11    to: "recipient@example.com",
12    subject: "Agent Communication",
13    text: "This is an outbound message from your agent.",
14  });
15
16  console.log(`Message sent successfully with ID: ${confirmation.id}`);
17  return confirmation;
18}
19
20sendEmailFromAgentInbox().catch((error) => {
21  console.error(error);
22  process.exit(1);
23});

Response:

json
1{
2  "message_id": "<abc123@agentmail.to>",
3  "inbox_id": "auto-reply@agentmail.to",
4  "from_": "John Doe <john@example.com>",
5  "subject": "Hello",
6  "text": "Email body content..."
7}

Step 4: List and retrieve messages from AgentMail inbox

Query the agent's inbox to retrieve incoming messages—supplier responses, approvals, or updates—using AgentMail's list method with optional filtering. Paginate results and filter by labels to isolate relevant threads for downstream agent decision-making.

Fetch inbox messages

Response:

json
1{
2  "type": "message.received",
3  "message": {
4    "message_id": "<abc123@agentmail.to>",
5    "inbox_id": "auto-reply@agentmail.to",
6    "from_": "John Doe <john@example.com>",
7    "subject": "Hello",
8    "text": "Email body content..."
9  }
10}

Step 5: Reply to messages and maintain conversation threads

AgentMail's reply method allows your agent to respond to incoming emails within the same thread, preserving conversation context for stakeholders. Use reply_all to notify all participants and include optional attachments or HTML formatting for richer communication.

Reply within thread

typescript
1import { AgentMailClient } from "agentmail";
2
3const client = new AgentMailClient({ apiKey: "YOUR_API_KEY" });
4
5// Reply to a message within the same thread, preserving conversation context
6const reply = await client.inboxes.messages.reply(
7  "my_inbox@domain.com",
8  "<abc123@agentmail.to>",
9  {
10    text: "Thanks for reaching out! Here's my response.",
11    html: "<div dir=\"ltr\">Thanks for reaching out!<br /><br />Here's my detailed response.</div>",
12    attachments: [
13      {
14        content: "document.pdf"
15      }
16    ]
17  }
18);
19
20console.log(`Reply sent successfully with ID: ${reply.id}`);
21

Response:

json
1{
2  "type": "message.received",
3  "message": {
4    "message_id": "<abc123@agentmail.to>",
5    "inbox_id": "auto-reply@agentmail.to",
6    "from_": "John Doe <john@example.com>",
7    "subject": "Hello",
8    "text": "Email body content..."
9  }
10}

Step 6: Register webhooks for real-time AgentMail event notifications

Subscribe to incoming email events via AgentMail webhooks so your agent receives real-time notifications when new messages arrive. Store the webhook_id for management, and ensure your agent's event handler is idempotent to safely process duplicate deliveries.

Register webhook endpoint

typescript
1import { AgentMailClient } from "agentmail";
2import "dotenv/config";
3
4async function main() {
5  const client = new AgentMailClient({
6    apiKey: process.env.AGENTMAIL_API_KEY,
7  });
8
9  const inbox = await client.inboxes.create();
10  console.log(`Inbox created: ${inbox.id}`);
11  console.log("Webhook registration not available in current API — webhooks are managed via dashboard or future API endpoints.");
12  console.log("For idempotent event handling, implement message deduplication using message IDs.");
13}
14
15main().catch((error) => {
16  console.error(error);
17  process.exit(1);
18});

Response:

json
1{
2  "type": "event",
3  "event_type": "event.name",
4  "event_id": "evt_123abc..."
5}
6
7{
8  "type": "message.received",
9  "message": {
10    "message_id": "<abc123@agentmail.to>",
11    "inbox_id": "auto-reply@agentmail.to",
12    "from_": "John Doe <john@example.com>",
13    "subject": "Hello",
14    "text": "Email body content..."
15  }
16}

Common pitfalls when using AgentMail

  • Missing checkpoint-resume for long-running workflows. Production agent workflows handling multi-day email approval cycles must persist inbox state and message IDs after each agent decision. Without checkpoints, network failures or retries risk duplicate sends or lost context. Store the last processed message_id and thread_id in durable state.
  • Uncontrolled outbound email volume. Agents can accidentally send hundreds of emails if retry logic or loop conditions are misconfigured. Always rate-limit sends per inbox, log every send attempt, and implement approval gates for bulk operations to prevent reputation damage and compliance violations.
  • Ignoring webhook delivery idempotency. AgentMail may deliver webhook events multiple times during transient failures. Your agent's event handler must deduplicate by event_id and store processed event IDs in a cache (Redis, DynamoDB) to avoid double-processing replies or triggering duplicate downstream actions.
  • No governance or approval flow on sensitive emails. Agents sending contract terminations or payment authorizations without human review expose organizations to legal and financial risk. Implement per-inbox approval policies, audit logging for every message, and role-based access control aligned with your compliance framework before scaling to production.

Ready to equip your agent with production-grade email? Get started with AgentMail and enable real inbox automation in minutes.

Documentation references

The code examples in this tutorial are grounded in the following docs pages:

Ready to give your agents real email access?

Join leading developers using AgentMail to enable AI agents to send, receive, and search email natively via API.

Read More Blog Posts

AgentMailAgentMail

Actionable email strategies for agent developers

© 2026 AgentMail, Inc. All rights reserved.