Back to AI guides

AgentMail: an email API built for AI agents

Stanley Ulili
Updated on March 23, 2026

AgentMail is an email API designed from the ground up for AI agents rather than human users. It lets agents create inboxes on demand, send and receive email through SDKs in Python and TypeScript, access structured message data including sender, subject, plain text and HTML body, attachments, and metadata, and manage thread state, labels, and read/unread status through code.

Why not use Gmail

Using a consumer email provider for agent automation is possible but introduces friction at every step. Services like Gmail are built around a graphical interface. Programmatic interaction requires OAuth 2.0, app-specific passwords, and Google Cloud Console configuration. These setups are fragile and can trigger security measures like captchas or account lockouts.

AgentMail's pricing is based on email volume rather than inbox count, which makes it practical to create a large number of inboxes for different agents or tasks without significant cost. It also includes features absent from consumer providers, including Pods for isolating customer data in multi-tenant applications and WebSockets for real-time event streaming, which avoids the need to constantly poll for new messages.

Setting up an inbox

Creating an inbox

After creating an account at agentmail.io, navigate to Inboxes in the dashboard sidebar and click + Create Inbox. Each inbox gets a unique email address. On the free plan, the domain defaults to agentmail.to.

AgentMail dashboard showing the Inboxes page with a newly created email address, claude-bs-test@agentmail.to

Generating an API key

In the dashboard, navigate to API Keys and click + Create API Key. Give the key a descriptive name and click Create. Copy the key immediately; it will not be shown again.

Installing the CLI

 
pip install agentmail

Add the API key to your shell environment:

 
export AGENTMAIL_API_KEY="your_api_key_here"

Restart the terminal or source the shell config file for the change to take effect. Verify the installation:

 
agentmail --help

Terminal window showing the output of agentmail --help with the available API resources and commands

Adding the Claude Code skill

A pre-built skill for Claude Code is available that teaches the agent to use the agentmail CLI without requiring a manual explanation in every prompt:

 
bunx skills add https://github.com/agentmail-to/agentmail-skills.git

Common operations with Claude Code

With the skill installed, Claude Code can perform email tasks from natural language prompts.

Listing inboxes: Asking "what agentmail inboxes do I have" causes the agent to run agentmail inboxes list and format the result as a table.

Sending email: A prompt like "send an email from the agentmail address to me@example.com with the top 3 matcha cafes in Kings Cross" leads the agent to research the topic, compose an email, and send it using agentmail inboxes:messages send with the appropriate to, from, subject, and body parameters.

Gmail inbox showing the received email from the AgentMail address with the subject "Top 3 Matcha Spots in Kings Cross"

Completing a newsletter subscription: After entering an agent's email address on a subscription form, the confirmation email arrives in the AgentMail inbox. Prompting Claude Code to "check your agentmail inbox and complete the subscription to Node Weekly" causes the agent to list messages, find the verification email, parse the confirmation link, and follow it programmatically.

Summarizing forwarded email: Forwarding emails from a personal account to the agent's address and then prompting "summarise all the emails forwarded to my agentmail address" produces a per-email summary. This is useful for digests, extracting key information, or handling a high volume of incoming messages.

Building a custom polling agent

A general-purpose agent like Claude Code works well for interactive tasks. For a persistent agent that processes email continuously, a dedicated script offers more control. The following TypeScript example polls an inbox every 30 seconds, detects new unread messages, fetches thread history for context, generates a reply using Claude, sends it, and labels the original message to avoid processing it again.

Project structure and polling loop

index.ts
import { AgentMailClient } from "agentmail";
import Anthropic from "@anthropic-ai/sdk";

const agentmail = new AgentMailClient({
    apiKey: process.env.AGENTMAIL_API_KEY!,
});
const claude = new Anthropic();

const INBOX_ID = "claude-bs-test@agentmail.to";
const REPLIED_LABEL = "AI_REPLIED";
const POLL_INTERVAL_MS = 30000;

async function main() {
    console.log(`Starting email agent for ${INBOX_ID}...`);

    while (true) {
        try {
            await processMessages();
        } catch (error) {
            console.error(`[${new Date().toISOString()}] Error:`, error);
        }
        await new Promise(resolve => setTimeout(resolve, POLL_INTERVAL_MS));
    }
}

main();

Processing messages and thread context

The processMessages function fetches all messages from the inbox, filters for unread messages without the AI_REPLIED label, retrieves the full thread history for each using agentmail.inboxes.threads.get(), generates a reply with that context, sends it, and then applies the AI_REPLIED label via agentmail.inboxes.messages.update().

Fetching the full thread before generating a reply is the step that makes conversations coherent. Without it, the agent replies to each email in isolation and loses track of what has already been said.

Reply generation

Code snippet from the generateReply function showing the system prompt given to Claude to define its behavior as a friendly email assistant

index.ts
async function generateReply(message: any, threadHistory: string): Promise<string> {
    const userContent = `Please write a warm and friendly reply to this email:

From: ${message.from}
Subject: ${message.subject || "(no subject)"}

${message.text || message.html}

${threadHistory ? `\nThread history:\n${threadHistory}` : ""}`;

    const response = await claude.messages.create({
        model: "claude-haiku-4-5",
        max_tokens: 1024,
        system: "You are a warm, friendly email assistant. Always respond in the same language as the original email.",
        messages: [{ role: "user", content: userContent }],
    });

    return response.content[0].type === "text" ? response.content[0].text : "";
}

The system prompt defines the agent's persona and ensures consistent tone across replies. The thread history appended to each prompt gives the model the full conversational context it needs to respond appropriately.

Running the agent

 
bun run index.ts

The script logs its polling activity to the terminal. Sending an email to the agent's address triggers a reply within 30 seconds. Replying to that response continues the thread, and the agent uses the accumulated context in each subsequent reply.

Email client showing the context-aware reply from the custom AI agent, demonstrating a complete successful interaction

Final thoughts

AgentMail handles the infrastructure concerns that make consumer email providers impractical for agentic workflows: OAuth complexity, API stability, per-inbox pricing, and the absence of features like real-time streaming. The combination of a clean SDK, a dedicated CLI, and support for thread management gives agents a reliable foundation for email-based automation.

The examples above, newsletter management, summarization, and automated replies, represent straightforward entry points. More complex workflows, like processing email attachments, routing messages between specialized agents, or integrating with calendar systems through email invites, follow from the same API surface.

Documentation and SDK references are available at agentmail.io.

Got an article suggestion? Let us know
Licensed under CC-BY-NC-SA

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.