Smithery Logo
MCPsSkillsDocsPricing
Login
NewFlame, an assistant that learns and improves. Available onTelegramSlack
    agentmail-to

    agentmail

    agentmail-to/agentmail
    Communication

    About

    SKILL.md

    Install

    • Telegram
      Telegram
    • Slack
      Slack
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    • Download skill
    ├─
    ├─
    └─
    Smithery Logo

    Give agents more agency

    Resources

    DocumentationPrivacy PolicySystem Status

    Company

    PricingAboutBlog

    Connect

    © 2026 Smithery. All rights reserved.

    About

    Build email agents using AgentMail API...

    SKILL.md

    AgentMail

    AgentMail is an API-first email platform for AI agents. Unlike traditional email services, it's designed for two-way conversations, allowing agents to send, receive, and reply to emails autonomously.

    Quick Start

    Installation

    # Python
    pip install agentmail
    
    # Node.js
    npm install agentmail
    

    Initialize Client

    from agentmail import AgentMail
    
    client = AgentMail()  # Uses AGENTMAIL_API_KEY from environment
    
    import { AgentMailClient } from "agentmail";
    
    const client = new AgentMailClient();  // Uses AGENTMAIL_API_KEY from environment
    

    Create Inbox and Send Email

    # Create inbox (use client_id for idempotency)
    inbox = client.inboxes.create(
        username="my-agent",
        client_id="my-agent-inbox"
    )
    print(f"Created: {inbox.inbox_id}")  # e.g., my-agent@agentmail.to
    
    # Send email (always include both text and html)
    client.inboxes.messages.send(
        inbox_id=inbox.inbox_id,
        to=["user@example.com"],
        subject="Hello from my agent",
        text="Plain text version",
        html="<p>HTML version</p>",
        labels=["outreach"]
    )
    
    const inbox = await client.inboxes.create({
      username: "my-agent",
      clientId: "my-agent-inbox"
    });
    
    await client.inboxes.messages.send(inbox.inboxId, {
      to: ["user@example.com"],
      subject: "Hello from my agent",
      text: "Plain text version",
      html: "<p>HTML version</p>",
      labels: ["outreach"]
    });
    

    Resource Hierarchy

    Organization (top-level container)
    └── Pod (optional, for multi-tenancy)
        └── Inbox (email account, e.g., agent@agentmail.to)
            └── Thread (conversation, auto-created)
                └── Message (individual email)
                    └── Attachment (files)
    

    Core Concepts

    Resource Purpose
    Organization Top-level container for all resources
    Inbox Email account (e.g., agent@agentmail.to)
    Message Individual email with text, html, attachments
    Thread Conversation grouping (auto-created)
    Webhook Event notifications via HTTP POST
    WebSocket Persistent bidirectional connection
    Pod Multi-tenant isolation (optional)
    Domain Custom domain with SPF/DKIM/DMARC
    Draft Unsent message for review
    Labels String tags for filtering and state management

    Common Workflows

    1. Reply to Email

    client.inboxes.messages.reply(
        inbox_id="agent@agentmail.to",
        message_id="msg_xxx",
        text="Thanks for your message!",
        html="<p>Thanks for your message!</p>"
    )
    
    await client.inboxes.messages.reply("agent@agentmail.to", "msg_xxx", {
      text: "Thanks for your message!",
      html: "<p>Thanks for your message!</p>"
    });
    

    2. List Messages with Label Filter

    messages = client.inboxes.messages.list(
        inbox_id="agent@agentmail.to",
        labels=["unread", "important"]
    )
    for msg in messages.messages:
        print(f"{msg.subject} from {msg.from_}")
    
    const messages = await client.inboxes.messages.list("agent@agentmail.to", {
      labels: ["unread", "important"]
    });
    for (const msg of messages.messages) {
      console.log(`${msg.subject} from ${msg.from}`);
    }
    

    3. Update Labels on Message

    client.inboxes.messages.update(
        inbox_id="agent@agentmail.to",
        message_id="msg_xxx",
        add_labels=["processed"],
        remove_labels=["unread"]
    )
    
    await client.inboxes.messages.update("agent@agentmail.to", "msg_xxx", {
      addLabels: ["processed"],
      removeLabels: ["unread"]
    });
    

    4. List Threads Org-Wide

    # Query all threads across all inboxes (for supervisor agents)
    all_threads = client.threads.list()
    
    # Or per inbox
    inbox_threads = client.inboxes.threads.list(inbox_id="agent@agentmail.to")
    
    // Query all threads across all inboxes (for supervisor agents)
    const allThreads = await client.threads.list();
    
    // Or per inbox
    const inboxThreads = await client.inboxes.threads.list("agent@agentmail.to");
    

    5. Send Attachment

    import base64
    
    with open("report.pdf", "rb") as f:
        content = base64.b64encode(f.read()).decode()
    
    client.inboxes.messages.send(
        inbox_id="agent@agentmail.to",
        to=["user@example.com"],
        subject="Report attached",
        text="Please see attached.",
        attachments=[{
            "content": content,
            "filename": "report.pdf",
            "content_type": "application/pdf"
        }]
    )
    
    import * as fs from "fs";
    
    const content = fs.readFileSync("report.pdf").toString("base64");
    
    await client.inboxes.messages.send("agent@agentmail.to", {
      to: ["user@example.com"],
      subject: "Report attached",
      text: "Please see attached.",
      attachments: [{
        content,
        filename: "report.pdf",
        contentType: "application/pdf"
      }]
    });
    

    Webhook Setup (Flask + ngrok)

    Webhooks notify your agent in real-time when events occur (e.g., new email received).

    Complete Example

    import os
    from threading import Thread
    from flask import Flask, request, Response
    import ngrok
    from agentmail import AgentMail
    
    app = Flask(__name__)
    client = AgentMail()
    port = 8080
    
    # Start ngrok tunnel
    listener = ngrok.forward(port, authtoken_from_env=True)
    webhook_url = f"{listener.url()}/webhooks"
    
    # Create inbox and webhook idempotently
    client.inboxes.create(username="webhook-agent", client_id="webhook-agent-inbox")
    client.webhooks.create(
        url=webhook_url,
        event_types=["message.received"],
        client_id="webhook-agent-webhook"
    )
    
    @app.route("/webhooks", methods=["POST"])
    def receive_webhook():
        # Return 200 immediately, process in background
        Thread(target=process_webhook, args=(request.json,)).start()
        return Response(status=200)
    
    def process_webhook(payload):
        event_type = payload["event_type"]
        if event_type == "message.received":
            message = payload["message"]
            print(f"New email from {message['from']}: {message['subject']}")
            
            # Reply to the message
            client.inboxes.messages.reply(
                inbox_id=message["inbox_id"],
                message_id=message["message_id"],
                text="Thanks for your email! I'll get back to you soon."
            )
    
    if __name__ == "__main__":
        print(f"Webhook URL: {webhook_url}")
        app.run(port=port)
    

    Webhook Event Types

    • message.received - New email arrived (includes full Thread + Message data)
    • message.sent - Email was sent
    • message.delivered - Email was delivered to recipient's server
    • message.bounced - Email failed to deliver
    • message.complained - Recipient marked as spam
    • message.rejected - Email rejected before sending
    • domain.verified - Custom domain verified

    See references/webhook-events.md for payload structures.

    WebSocket Real-time Events

    WebSockets provide real-time events without needing a public URL.

    Async Pattern

    import asyncio
    from agentmail import AsyncAgentMail, Subscribe, MessageReceivedEvent
    
    client = AsyncAgentMail()
    
    async def main():
        async with client.websockets.connect() as socket:
            await socket.send_subscribe(Subscribe(
                inbox_ids=["agent@agentmail.to"]
            ))
            
            async for event in socket:
                if isinstance(event, MessageReceivedEvent):
                    print(f"New email: {event.message.subject}")
    
    asyncio.run(main())
    
    const socket = await client.websockets.connect();
    
    socket.on("open", () => {
      socket.sendSubscribe({
        type: "subscribe",
        inboxIds: ["agent@agentmail.to"]
      });
    });
    
    socket.on("message", (event) => {
      if (event.type === "message_received") {
        console.log(`New email: ${event.message.subject}`);
      }
    });
    

    AI Agent Integration

    Use agentmail-toolkit to give AI agents email capabilities.

    Installation

    pip install agentmail-toolkit
    

    OpenAI Agents

    from agentmail import AgentMail
    from agentmail_toolkit.openai import AgentMailToolkit
    from agents import Agent, Runner
    
    client = AgentMail()
    toolkit = AgentMailToolkit(client)
    
    agent = Agent(
        name="Email Agent",
        instructions=f"""You are an email agent. Your inbox is agent@agentmail.to.
        You can send, receive, and reply to emails.""",
        tools=toolkit.get_tools()
    )
    
    response = Runner.run(agent, [{"role": "user", "content": "Send a hello email to user@example.com"}])
    

    Langchain

    from langchain_openai import ChatOpenAI
    from langgraph.prebuilt import create_react_agent
    from agentmail_toolkit.langchain import AgentMailToolkit
    
    agent = create_react_agent(
        model=ChatOpenAI(model="gpt-4o"),
        tools=AgentMailToolkit().get_tools()
    )
    

    Best Practices

    Idempotency

    Always use client_id on create operations to prevent duplicates:

    # Safe to run multiple times - won't create duplicates
    inbox = client.inboxes.create(
        username="my-agent",
        client_id="user-123-primary-inbox"
    )
    
    webhook = client.webhooks.create(
        url="https://example.com/webhooks",
        event_types=["message.received"],
        client_id="user-123-webhook"
    )
    

    Webhook Handling

    Always return 200 immediately and process in background:

    @app.route("/webhooks", methods=["POST"])
    def webhook():
        Thread(target=process, args=(request.json,)).start()
        return Response(status=200)  # Return immediately!
    

    Reply Extraction

    Use extracted_text / extracted_html fields for clean reply content (removes quoted text):

    message = client.inboxes.messages.get(inbox_id, message_id)
    clean_reply = message.extracted_text  # Just the new content
    full_email = message.text  # Includes quoted replies
    

    Or use Talon library for more control:

    from talon import quotations
    clean = quotations.extract_from_plain(email_text)
    

    Critical Gotchas

    1. Bounced/complained addresses are permanently blocked - AgentMail prevents sending to them to protect your reputation

    2. Keep bounce rate < 4% - Or your account goes under review

    3. AWS Route 53 DKIM records - Must split into two quoted strings with NO space:

      Correct: "first-part""second-part"
      Wrong:   "first-part" "second-part"  (space breaks it)
      
    4. Only one SPF record per domain - Merge multiple services:

      v=spf1 include:spf.agentmail.to include:other.com ~all
      
    5. message.received is the only webhook with full Thread + Message data - Other events have minimal metadata

    6. Pods cannot be deleted with existing resources - Delete all inboxes/domains in the pod first

    7. Inboxes cannot be moved between pods - Create new inbox in target pod

    IMAP/SMTP Access

    For email client integration:

    Protocol Host Port Auth
    IMAP imap.agentmail.to 993 (SSL) inbox email + API key
    SMTP smtp.agentmail.to 465 (SSL) inbox email + API key

    Additional Resources

    • API Reference - Complete method signatures
    • Webhook Events - Event payloads
    • Advanced Examples - Agent patterns
    • Official Docs
    • Console
    Recommended Servers
    AgentMail
    AgentMail
    Agent Safe Message MCP
    Agent Safe Message MCP
    Guard Mail
    Guard Mail
    Repository
    agentmail-to/agentmail-claude-skill
    Files