agentmail-sdk

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

AgentMail SDK

AgentMail SDK

AgentMail is an API-first email platform built for AI agents. Unlike transactional email APIs (Resend, SendGrid) that focus on one-way sending, AgentMail provides full two-way email inboxes that agents can create, send from, receive into, and manage programmatically.
Key capabilities:
  • Instant inbox creation (milliseconds, no domain setup needed)
  • Two-way conversations with native thread management
  • Reply extraction (
    extracted_text
    ) strips quoted history automatically
  • WebSocket and webhook support for real-time inbound
  • Human-in-the-loop drafts for agent oversight
  • Multi-tenant isolation with pods
  • Allow/block lists for sender filtering
  • IMAP and SMTP access for legacy integrations
AgentMail是专为AI Agent打造的API优先邮件平台。与专注于单向发送的事务性邮件API(如Resend、SendGrid)不同,AgentMail提供完整的双向邮箱,支持Agent程序化创建、发送、接收及管理邮件。
核心功能:
  • 即时创建邮箱(毫秒级,无需域名配置)
  • 支持双向对话及原生线程管理
  • 回复提取(
    extracted_text
    )自动去除引用历史
  • 支持WebSocket与Webhook实现实时收件通知
  • 支持人工介入审核的草稿功能
  • 通过Pods实现多租户隔离
  • 允许/阻止列表用于发件人过滤
  • 支持IMAP与SMTP接入以兼容遗留系统

Installation and setup

安装与配置

bash
undefined
bash
undefined

Python

Python

pip install agentmail
pip install agentmail

TypeScript / Node.js

TypeScript / Node.js

npm install agentmail

Get your API key from https://console.agentmail.to/ or via the Agent sign-up API (see below).

**Python:**
```python
from agentmail import AgentMail
client = AgentMail(api_key="YOUR_API_KEY")
npm install agentmail

从https://console.agentmail.to/ 或通过Agent注册API获取您的API密钥(见下文)。

**Python:**
```python
from agentmail import AgentMail
client = AgentMail(api_key="YOUR_API_KEY")

Or set AGENTMAIL_API_KEY env var and omit api_key:

或设置AGENTMAIL_API_KEY环境变量,无需传入api_key参数:

client = AgentMail()

client = AgentMail()


**TypeScript:**
```typescript
import { AgentMailClient } from "agentmail";
const client = new AgentMailClient({ apiKey: "YOUR_API_KEY" });

**TypeScript:**
```typescript
import { AgentMailClient } from "agentmail";
const client = new AgentMailClient({ apiKey: "YOUR_API_KEY" });

Agent sign-up (programmatic, no console needed)

Agent注册(程序化,无需控制台)

Create an account and get an API key entirely from code. No browser required.
Requires
agentmail>=0.4.15
(Python) /
agentmail>=0.x
(TypeScript). If your installed SDK raises
AttributeError: 'AgentMail' object has no attribute 'agent'
, upgrade first.
python
client = AgentMail()  # no api_key needed for sign-up
response = client.agent.sign_up(
    human_email="you@example.com",
    username="my-agent",
)
完全通过代码创建账户并获取API密钥,无需浏览器。
要求
agentmail>=0.4.15
(Python版)/
agentmail>=0.x
(TypeScript版)。若您安装的SDK提示
AttributeError: 'AgentMail' object has no attribute 'agent'
,请先升级。
python
client = AgentMail()  # 注册无需传入api_key
response = client.agent.sign_up(
    human_email="you@example.com",
    username="my-agent",
)

response.api_key -> store this securely

response.api_key -> 请安全存储

response.inbox_id -> my-agent@agentmail.to

response.inbox_id -> my-agent@agentmail.to

response.organization_id

response.organization_id

Verify with OTP sent to your email

使用发送至您邮箱的OTP验证码完成验证

client = AgentMail(api_key=response.api_key) client.agent.verify(otp_code="123456")

```typescript
const client = new AgentMailClient();
const response = await client.agent.signUp({
    humanEmail: "you@example.com",
    username: "my-agent",
});
// response.apiKey, response.inboxId, response.organizationId

const authedClient = new AgentMailClient({ apiKey: response.apiKey });
await authedClient.agent.verify({ otpCode: "123456" });
The sign-up endpoint is idempotent: calling again with the same email rotates the API key and resends the OTP.
client = AgentMail(api_key=response.api_key) client.agent.verify(otp_code="123456")

```typescript
const client = new AgentMailClient();
const response = await client.agent.signUp({
    humanEmail: "you@example.com",
    username: "my-agent",
});
// response.apiKey, response.inboxId, response.organizationId

const authedClient = new AgentMailClient({ apiKey: response.apiKey });
await authedClient.agent.verify({ otpCode: "123456" });
注册接口具有幂等性:使用同一邮箱再次调用会轮换API密钥并重发OTP验证码。

Inboxes

邮箱管理

Create scalable inboxes on-demand. Each inbox has a unique email address. No domain verification needed for
@agentmail.to
.
python
from agentmail.inboxes.types import CreateInboxRequest
按需创建可扩展的邮箱,每个邮箱拥有唯一的邮件地址。使用
@agentmail.to
域名无需验证。
python
from agentmail.inboxes.types import CreateInboxRequest

Create inbox (auto-generated address)

创建邮箱(自动生成地址)

inbox = client.inboxes.create()
inbox = client.inboxes.create()

inbox.inbox_id, inbox.email

inbox.inbox_id, inbox.email

Create with options. All create kwargs go inside a CreateInboxRequest.

带选项创建,所有创建参数需放入CreateInboxRequest对象中

inbox = client.inboxes.create( request=CreateInboxRequest( username="support", domain="yourdomain.com", # optional, defaults to agentmail.to display_name="Support Agent", client_id="support-v1", # idempotency key, safe to retry ), )
inbox = client.inboxes.create( request=CreateInboxRequest( username="support", domain="yourdomain.com", # 可选,默认值为agentmail.to display_name="Support Agent", client_id="support-v1", # 幂等键,可安全重试 ), )

List all inboxes

列出所有邮箱

inboxes = client.inboxes.list()
inboxes = client.inboxes.list()

Paginate: client.inboxes.list(limit=20, page_token=inboxes.next_page_token)

分页查询:client.inboxes.list(limit=20, page_token=inboxes.next_page_token)

Get, update, delete

获取、更新、删除邮箱

inbox = client.inboxes.get(inbox_id="support@agentmail.to") client.inboxes.update(inbox_id="support@agentmail.to", display_name="New Name") client.inboxes.delete(inbox_id="support@agentmail.to")

```typescript
const inbox = await client.inboxes.create({
    username: "support",
    domain: "yourdomain.com",
    displayName: "Support Agent",
    clientId: "support-v1",
});

const inboxes = await client.inboxes.list();
const fetched = await client.inboxes.get("support@agentmail.to");
await client.inboxes.update("support@agentmail.to", { displayName: "New Name" });
await client.inboxes.delete("support@agentmail.to");
Custom domains require a paid plan. Default
@agentmail.to
inboxes are free.
inbox = client.inboxes.get(inbox_id="support@agentmail.to") client.inboxes.update(inbox_id="support@agentmail.to", display_name="New Name") client.inboxes.delete(inbox_id="support@agentmail.to")

```typescript
const inbox = await client.inboxes.create({
    username: "support",
    domain: "yourdomain.com",
    displayName: "Support Agent",
    clientId: "support-v1",
});

const inboxes = await client.inboxes.list();
const fetched = await client.inboxes.get("support@agentmail.to");
await client.inboxes.update("support@agentmail.to", { displayName: "New Name" });
await client.inboxes.delete("support@agentmail.to");
自定义域名需付费套餐,默认
@agentmail.to
邮箱免费使用。

Messages

邮件管理

Send

发送邮件

Always provide both
text
and
html
for best deliverability. Maximum 50 recipients across to + cc + bcc combined.
python
sent = client.inboxes.messages.send(
    inbox_id="agent@agentmail.to",
    to="recipient@example.com",       # string or list
    subject="Hello from AgentMail",
    text="Plain text body",
    html="<p>HTML body</p>",          # optional but recommended
    cc="cc@example.com",              # optional, string or list
    bcc="bcc@example.com",            # optional, string or list
    reply_to="replies@example.com",   # optional
    labels=["outreach"],              # optional
    attachments=[{                    # optional
        "filename": "report.pdf",
        "content": base64_content,    # Base64-encoded
        "content_type": "application/pdf",
    }],
)
为确保最佳投递率,请同时提供
text
html
内容。收件人总数(to + cc + bcc)最多50个。
python
sent = client.inboxes.messages.send(
    inbox_id="agent@agentmail.to",
    to="recipient@example.com",       # 字符串或列表
    subject="Hello from AgentMail",
    text="Plain text body",
    html="<p>HTML body</p>",          # 可选但推荐提供
    cc="cc@example.com",              # 可选,字符串或列表
    bcc="bcc@example.com",            # 可选,字符串或列表
    reply_to="replies@example.com",   # 可选
    labels=["outreach"],              # 可选
    attachments=[{                    # 可选
        "filename": "report.pdf",
        "content": base64_content,    # Base64编码内容
        "content_type": "application/pdf",
    }],
)

sent.message_id, sent.thread_id

sent.message_id, sent.thread_id


```typescript
const sent = await client.inboxes.messages.send("agent@agentmail.to", {
    to: "recipient@example.com",
    subject: "Hello from AgentMail",
    text: "Plain text body",
    html: "<p>HTML body</p>",
    cc: "cc@example.com",
    labels: ["outreach"],
    attachments: [{
        filename: "report.pdf",
        content: base64Content,
        contentType: "application/pdf",
    }],
});

```typescript
const sent = await client.inboxes.messages.send("agent@agentmail.to", {
    to: "recipient@example.com",
    subject: "Hello from AgentMail",
    text: "Plain text body",
    html: "<p>HTML body</p>",
    cc: "cc@example.com",
    labels: ["outreach"],
    attachments: [{
        filename: "report.pdf",
        content: base64Content,
        contentType: "application/pdf",
    }],
});

List and get

列出与获取邮件

python
undefined
python
undefined

List messages in an inbox. Note: .list() returns MessageItem objects

列出邮箱中的邮件。注意:.list()返回MessageItem对象

(metadata only — subject, from, labels, timestamps, etc.) with NO body

仅包含元数据——主题、发件人、标签、时间戳等,不包含邮件正文

content. To read .text / .html / .extracted_text you must fetch the full

如需读取.text / .html / .extracted_text内容,需调用.get()获取完整邮件

message with .get().

response = client.inboxes.messages.list( inbox_id="agent@agentmail.to", limit=10, # optional, default varies labels=["unread"], # optional, filter by label ) for item in response.messages: # item is a MessageItem (metadata only). Fetch the full Message for body: msg = client.inboxes.messages.get( inbox_id=item.inbox_id, message_id=item.message_id, ) # Use extracted_text for reply content without quoted history content = msg.extracted_text or msg.text print(msg.subject, content)
response = client.inboxes.messages.list( inbox_id="agent@agentmail.to", limit=10, # 可选,默认值不定 labels=["unread"], # 可选,按标签过滤 ) for item in response.messages: # item为MessageItem(仅元数据),需获取完整Message对象以读取正文 msg = client.inboxes.messages.get( inbox_id=item.inbox_id, message_id=item.message_id, ) # 使用extracted_text获取去除引用历史的回复内容 content = msg.extracted_text or msg.text print(msg.subject, content)

Paginate

分页查询

while response.next_page_token: response = client.inboxes.messages.list( inbox_id="agent@agentmail.to", page_token=response.next_page_token, )
while response.next_page_token: response = client.inboxes.messages.list( inbox_id="agent@agentmail.to", page_token=response.next_page_token, )

Get a specific message

获取指定邮件

msg = client.inboxes.messages.get( inbox_id="agent@agentmail.to", message_id="abc123@agentmail.to", )
msg = client.inboxes.messages.get( inbox_id="agent@agentmail.to", message_id="abc123@agentmail.to", )

Get raw MIME content

获取原始MIME内容

raw = client.inboxes.messages.get_raw( inbox_id="agent@agentmail.to", message_id="abc123@agentmail.to", )

```typescript
const response = await client.inboxes.messages.list("agent@agentmail.to", {
    limit: 10,
    labels: ["unread"],
});

const msg = await client.inboxes.messages.get(
    "agent@agentmail.to",
    "<abc123@agentmail.to>",
);
Important: when processing inbound replies, always use
extracted_text
/
extracted_html
instead of
text
/
html
. These fields strip quoted history and signatures, giving you only the new content. This is powered by Talon reply extraction.
Also note: some email clients (Gmail, Outlook) send forwards as HTML-only. Always treat
html
as the primary content source and
text
as optional.
raw = client.inboxes.messages.get_raw( inbox_id="agent@agentmail.to", message_id="abc123@agentmail.to", )

```typescript
const response = await client.inboxes.messages.list("agent@agentmail.to", {
    limit: 10,
    labels: ["unread"],
});

const msg = await client.inboxes.messages.get(
    "agent@agentmail.to",
    "<abc123@agentmail.to>",
);
重要提示:处理收件回复时,请始终使用
extracted_text
/
extracted_html
而非
text
/
html
。这些字段会自动去除引用历史和签名,仅保留新增内容,由Talon回复提取技术提供支持。
此外注意:部分邮件客户端(如Gmail、Outlook)仅以HTML格式发送转发邮件,请始终将
html
视为主要内容源,
text
作为可选内容。

Reply

回复邮件

Replying adds the message to the existing thread.
python
reply = client.inboxes.messages.reply(
    inbox_id="agent@agentmail.to",
    message_id="<abc123@agentmail.to>",
    text="Thanks for your email!",
    html="<p>Thanks for your email!</p>",   # optional
    attachments=[...],                       # optional
    reply_all=False,                         # optional, defaults to False
)
typescript
const reply = await client.inboxes.messages.reply(
    "agent@agentmail.to",
    "<abc123@agentmail.to>",
    { text: "Thanks for your email!" },
);
回复会将邮件添加至现有对话线程。
python
reply = client.inboxes.messages.reply(
    inbox_id="agent@agentmail.to",
    message_id="<abc123@agentmail.to>",
    text="Thanks for your email!",
    html="<p>Thanks for your email!</p>",   # 可选
    attachments=[...],                       # 可选
    reply_all=False,                         # 可选,默认值为False
)
typescript
const reply = await client.inboxes.messages.reply(
    "agent@agentmail.to",
    "<abc123@agentmail.to>",
    { text: "Thanks for your email!" },
);

Forward

转发邮件

python
client.inboxes.messages.forward(
    inbox_id="agent@agentmail.to",
    message_id="<abc123@agentmail.to>",
    to="colleague@example.com",
    text="FYI, see below.",       # optional prepended text
)
typescript
await client.inboxes.messages.forward(
    "agent@agentmail.to",
    "<abc123@agentmail.to>",
    {
        to: "colleague@example.com",
        text: "FYI, see below.",
    },
);
python
client.inboxes.messages.forward(
    inbox_id="agent@agentmail.to",
    message_id="<abc123@agentmail.to>",
    to="colleague@example.com",
    text="FYI, see below.",       # 可选的前置文本
)
typescript
await client.inboxes.messages.forward(
    "agent@agentmail.to",
    "<abc123@agentmail.to>",
    {
        to: "colleague@example.com",
        text: "FYI, see below.",
    },
);

Update labels

更新标签

Use labels to track message processing state. AgentMail does not have a built-in "read/unread" flag. Use labels instead.
python
client.inboxes.messages.update(
    inbox_id="agent@agentmail.to",
    message_id="<abc123@agentmail.to>",
    add_labels=["processed", "replied"],
    remove_labels=["unread"],
)
typescript
await client.inboxes.messages.update(
    "agent@agentmail.to",
    "<abc123@agentmail.to>",
    {
        addLabels: ["processed", "replied"],
        removeLabels: ["unread"],
    },
);
使用标签追踪邮件处理状态。AgentMail无内置“已读/未读”标记,请使用标签替代。
python
client.inboxes.messages.update(
    inbox_id="agent@agentmail.to",
    message_id="<abc123@agentmail.to>",
    add_labels=["processed", "replied"],
    remove_labels=["unread"],
)
typescript
await client.inboxes.messages.update(
    "agent@agentmail.to",
    "<abc123@agentmail.to>",
    {
        addLabels: ["processed", "replied"],
        removeLabels: ["unread"],
    },
);

Attachments

附件处理

python
import base64
python
import base64

Send with attachment

发送带附件的邮件

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="See attached.", attachments=[{ "filename": "report.pdf", "content": content, "content_type": "application/pdf", }], )
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="See attached.", attachments=[{ "filename": "report.pdf", "content": content, "content_type": "application/pdf", }], )

Retrieve attachment from received message

从收到的邮件中获取附件

attachment = client.inboxes.messages.get_attachment( inbox_id="agent@agentmail.to", message_id="abc123@agentmail.to", attachment_id="att_456", )

```typescript
import { readFileSync } from "node:fs";

const content = readFileSync("report.pdf").toString("base64");

await client.inboxes.messages.send("agent@agentmail.to", {
    to: "user@example.com",
    subject: "Report attached",
    text: "See attached.",
    attachments: [{ filename: "report.pdf", content, contentType: "application/pdf" }],
});

const attachment = await client.inboxes.messages.getAttachment(
    "agent@agentmail.to",
    "<abc123@agentmail.to>",
    "att_456",
);
attachment = client.inboxes.messages.get_attachment( inbox_id="agent@agentmail.to", message_id="abc123@agentmail.to", attachment_id="att_456", )

```typescript
import { readFileSync } from "node:fs";

const content = readFileSync("report.pdf").toString("base64");

await client.inboxes.messages.send("agent@agentmail.to", {
    to: "user@example.com",
    subject: "Report attached",
    text: "See attached.",
    attachments: [{ filename: "report.pdf", content, contentType: "application/pdf" }],
});

const attachment = await client.inboxes.messages.getAttachment(
    "agent@agentmail.to",
    "<abc123@agentmail.to>",
    "att_456",
);

Threads

对话线程管理

Threads group related messages in a conversation. When you send a new message, a thread is created. Replies are added to the same thread automatically.
python
undefined
线程将对话中的相关邮件分组。发送新邮件时会创建线程,回复会自动添加至同一线程。
python
undefined

List threads in an inbox

列出邮箱中的线程

threads = client.inboxes.threads.list( inbox_id="agent@agentmail.to", labels=["unreplied"], # optional filter )
threads = client.inboxes.threads.list( inbox_id="agent@agentmail.to", labels=["unreplied"], # 可选过滤条件 )

Get a specific thread with all messages

获取包含所有邮件的指定线程

thread = client.inboxes.threads.get( inbox_id="agent@agentmail.to", thread_id="thd_123", ) for msg in thread.messages: print(msg.subject, msg.extracted_text)
thread = client.inboxes.threads.get( inbox_id="agent@agentmail.to", thread_id="thd_123", ) for msg in thread.messages: print(msg.subject, msg.extracted_text)

Org-wide thread listing (across all inboxes)

列出组织内所有线程(跨所有邮箱)

all_threads = client.threads.list()
all_threads = client.threads.list()

Delete a thread

删除线程

client.inboxes.threads.delete( inbox_id="agent@agentmail.to", thread_id="thd_123", )

```typescript
const threads = await client.inboxes.threads.list("agent@agentmail.to", {
    labels: ["unreplied"],
});

const thread = await client.inboxes.threads.get("agent@agentmail.to", "thd_123");

const allThreads = await client.threads.list();
client.inboxes.threads.delete( inbox_id="agent@agentmail.to", thread_id="thd_123", )

```typescript
const threads = await client.inboxes.threads.list("agent@agentmail.to", {
    labels: ["unreplied"],
});

const thread = await client.inboxes.threads.get("agent@agentmail.to", "thd_123");

const allThreads = await client.threads.list();

Drafts

草稿管理

Create drafts for human-in-the-loop approval. The agent composes a draft, a human reviews, then the draft is sent.
python
undefined
创建草稿用于人工介入审核:Agent编写草稿,人工审核后发送。
python
undefined

Create draft

创建草稿

draft = client.inboxes.drafts.create( inbox_id="agent@agentmail.to", to="recipient@example.com", subject="Pending approval", text="Draft content for review", html="<p>Draft content for review</p>", )
draft = client.inboxes.drafts.create( inbox_id="agent@agentmail.to", to="recipient@example.com", subject="Pending approval", text="Draft content for review", html="<p>Draft content for review</p>", )

List drafts

列出草稿

drafts = client.inboxes.drafts.list(inbox_id="agent@agentmail.to")
drafts = client.inboxes.drafts.list(inbox_id="agent@agentmail.to")

Get, update

获取、更新草稿

draft = client.inboxes.drafts.get(inbox_id="agent@agentmail.to", draft_id=draft.draft_id) client.inboxes.drafts.update( inbox_id="agent@agentmail.to", draft_id=draft.draft_id, text="Updated draft content", )
draft = client.inboxes.drafts.get(inbox_id="agent@agentmail.to", draft_id=draft.draft_id) client.inboxes.drafts.update( inbox_id="agent@agentmail.to", draft_id=draft.draft_id, text="Updated draft content", )

Send draft (converts to message, removes from drafts)

发送草稿(转换为邮件,从草稿列表移除)

client.inboxes.drafts.send(inbox_id="agent@agentmail.to", draft_id=draft.draft_id)
client.inboxes.drafts.send(inbox_id="agent@agentmail.to", draft_id=draft.draft_id)

Delete draft without sending

删除草稿不发送

client.inboxes.drafts.delete(inbox_id="agent@agentmail.to", draft_id=draft.draft_id)

```typescript
const draft = await client.inboxes.drafts.create("agent@agentmail.to", {
    to: "recipient@example.com",
    subject: "Pending approval",
    text: "Draft content",
});

await client.inboxes.drafts.send("agent@agentmail.to", draft.draftId, {});
client.inboxes.drafts.delete(inbox_id="agent@agentmail.to", draft_id=draft.draft_id)

```typescript
const draft = await client.inboxes.drafts.create("agent@agentmail.to", {
    to: "recipient@example.com",
    subject: "Pending approval",
    text: "Draft content",
});

await client.inboxes.drafts.send("agent@agentmail.to", draft.draftId, {});

Pods (multi-tenant isolation)

Pods(多租户隔离)

Pods provide isolated environments for SaaS platforms. Each pod has its own set of inboxes.
python
undefined
Pods为SaaS平台提供隔离环境,每个Pod拥有独立的邮箱集合。
python
undefined

Create pod per customer

为每个客户创建Pod

pod = client.pods.create( name="customer-acme", client_id="pod-acme-v1", # idempotent )
pod = client.pods.create( name="customer-acme", client_id="pod-acme-v1", # 幂等键 )

Create inbox within pod (pods.inboxes.create accepts flat kwargs)

在Pod内创建邮箱(pods.inboxes.create接受扁平参数)

inbox = client.pods.inboxes.create( pod_id=pod.pod_id, username="notifications", client_id="acme-notifications-v1", )
inbox = client.pods.inboxes.create( pod_id=pod.pod_id, username="notifications", client_id="acme-notifications-v1", )

List inboxes scoped to pod

列出Pod范围内的邮箱

inboxes = client.pods.inboxes.list(pod_id=pod.pod_id)
inboxes = client.pods.inboxes.list(pod_id=pod.pod_id)

List threads scoped to pod

列出Pod范围内的线程

threads = client.pods.threads.list(pod_id=pod.pod_id)
threads = client.pods.threads.list(pod_id=pod.pod_id)

List, get, delete pods

列出、获取、删除Pods

pods = client.pods.list() pod = client.pods.get(pod_id=pod.pod_id) client.pods.delete(pod_id=pod.pod_id)

```typescript
const pod = await client.pods.create({ name: "customer-acme", clientId: "pod-acme-v1" });
const inbox = await client.pods.inboxes.create(pod.podId, {
    username: "notifications",
    clientId: "acme-notifications-v1",
});
const inboxes = await client.pods.inboxes.list(pod.podId);
pods = client.pods.list() pod = client.pods.get(pod_id=pod.pod_id) client.pods.delete(pod_id=pod.pod_id)

```typescript
const pod = await client.pods.create({ name: "customer-acme", clientId: "pod-acme-v1" });
const inbox = await client.pods.inboxes.create(pod.podId, {
    username: "notifications",
    clientId: "acme-notifications-v1",
});
const inboxes = await client.pods.inboxes.list(pod.podId);

Allow/block lists

允许/阻止列表

Control which external senders can deliver to an inbox. Block list takes priority over allow list.
Lists are flat. Each entry is one
(direction, type, entry)
tuple — there is no batch update, no
.allow
/
.block
sub-namespace.
direction
is
"send"
,
"receive"
, or
"reply"
.
type
is
"allow"
or
"block"
.
python
undefined
控制哪些外部发件人可向邮箱投递邮件。阻止列表优先级高于允许列表。
列表为扁平结构,每个条目是一个
(direction, type, entry)
元组——无批量更新,无
.allow
/
.block
子命名空间。
direction
可选
"send"
"receive"
"reply"
type
可选
"allow"
"block"
python
undefined

Allow a sender on incoming mail

允许指定发件人向邮箱投递邮件

client.inboxes.lists.create( inbox_id="agent@agentmail.to", direction="receive", type="allow", entry="boss@company.com", )
client.inboxes.lists.create( inbox_id="agent@agentmail.to", direction="receive", type="allow", entry="boss@company.com", )

Block a sender on incoming mail

阻止指定发件人向邮箱投递邮件

client.inboxes.lists.create( inbox_id="agent@agentmail.to", direction="receive", type="block", entry="spammer@example.com", )
client.inboxes.lists.create( inbox_id="agent@agentmail.to", direction="receive", type="block", entry="spammer@example.com", )

List entries for one (direction, type) pair

列出指定(direction, type)组合下的所有条目

allow = client.inboxes.lists.list( inbox_id="agent@agentmail.to", direction="receive", type="allow", )
allow = client.inboxes.lists.list( inbox_id="agent@agentmail.to", direction="receive", type="allow", )

Check a single entry

查询单个条目

entry = client.inboxes.lists.get( inbox_id="agent@agentmail.to", direction="receive", type="allow", entry="boss@company.com", )
entry = client.inboxes.lists.get( inbox_id="agent@agentmail.to", direction="receive", type="allow", entry="boss@company.com", )

Remove an entry

删除条目

client.inboxes.lists.delete( inbox_id="agent@agentmail.to", direction="receive", type="allow", entry="boss@company.com", )

```typescript
await client.inboxes.lists.create(
    "agent@agentmail.to",
    "receive",
    "allow",
    { entry: "boss@company.com" },
);

await client.inboxes.lists.create(
    "agent@agentmail.to",
    "receive",
    "block",
    { entry: "spammer@example.com" },
);

const allow = await client.inboxes.lists.list(
    "agent@agentmail.to",
    "receive",
    "allow",
);

await client.inboxes.lists.delete(
    "agent@agentmail.to",
    "receive",
    "allow",
    "boss@company.com",
);
client.inboxes.lists.delete( inbox_id="agent@agentmail.to", direction="receive", type="allow", entry="boss@company.com", )

```typescript
await client.inboxes.lists.create(
    "agent@agentmail.to",
    "receive",
    "allow",
    { entry: "boss@company.com" },
);

await client.inboxes.lists.create(
    "agent@agentmail.to",
    "receive",
    "block",
    { entry: "spammer@example.com" },
);

const allow = await client.inboxes.lists.list(
    "agent@agentmail.to",
    "receive",
    "allow",
);

await client.inboxes.lists.delete(
    "agent@agentmail.to",
    "receive",
    "allow",
    "boss@company.com",
);

Domains

域名管理

Custom domains let agents send from your own domain (e.g.,
agent@yourdomain.com
). SPF, DKIM, and DMARC records are auto-generated. Requires paid plan.
python
undefined
自定义域名允许Agent使用您的自有域名发送邮件(如
agent@yourdomain.com
)。SPF、DKIM及DMARC记录会自动生成,需付费套餐。
python
undefined

Add domain. feedback_enabled is required: set True to route

添加域名。feedback_enabled为必填项:设为True可将退信/投诉通知路由至您的邮箱

bounce/complaint notifications to your inboxes.

domain = client.domains.create(domain="yourdomain.com", feedback_enabled=True)
domain = client.domains.create(domain="yourdomain.com", feedback_enabled=True)

domain.records -> list of VerificationRecord objects to add at your registrar

domain.records -> 需添加至域名注册商的VerificationRecord对象列表

Verify after DNS records are set

DNS记录设置完成后验证域名

client.domains.verify(domain_id=domain.domain_id)
client.domains.verify(domain_id=domain.domain_id)

List, get, delete

列出、获取、删除域名

domains = client.domains.list() domain = client.domains.get(domain_id=domain.domain_id) client.domains.delete(domain_id=domain.domain_id)

```typescript
const domain = await client.domains.create({
    domain: "yourdomain.com",
    feedbackEnabled: true,
});
await client.domains.verify(domain.domainId);
domains = client.domains.list() domain = client.domains.get(domain_id=domain.domain_id) client.domains.delete(domain_id=domain.domain_id)

```typescript
const domain = await client.domains.create({
    domain: "yourdomain.com",
    feedbackEnabled: true,
});
await client.domains.verify(domain.domainId);

Real-time events

实时事件

AgentMail supports both WebSockets and webhooks for real-time notifications. See
references/webhooks.md
and
references/websockets.md
for detailed setup and full code examples.
AgentMail支持WebSocket与Webhook两种实时通知方式。详细设置及完整代码示例请参考
references/webhooks.md
references/websockets.md

WebSockets (recommended for agents)

WebSocket(推荐Agent使用)

No public URL needed. Persistent connection with instant delivery.
Python (sync):
python
from agentmail import AgentMail, Subscribe, Subscribed, MessageReceivedEvent

client = AgentMail()
with client.websockets.connect() as socket:
    socket.send_subscribe(Subscribe(inbox_ids=["agent@agentmail.to"]))
    for event in socket:
        if isinstance(event, Subscribed):
            print(f"Subscribed to: {event.inbox_ids}")
        elif isinstance(event, MessageReceivedEvent):
            print(f"From: {event.message.from_}")
            print(f"Subject: {event.message.subject}")
            print(f"Body: {event.message.extracted_text}")
Python (async):
python
from agentmail import AsyncAgentMail, Subscribe, MessageReceivedEvent

client = AsyncAgentMail()
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):
            await process_email(event.message)
TypeScript:
typescript
const socket = await client.websockets.connect();
socket.on("open", () => {
    socket.sendSubscribe({ type: "subscribe", inboxIds: ["agent@agentmail.to"] });
});
socket.on("message", (event) => {
    // Use event.eventType (not event.type — event.type is always "event")
    if (event.eventType === "message.received") {
        // TypeScript uses .from directly; only Python needs .from_ (reserved keyword)
        console.log("From:", event.message.from);
        console.log("Subject:", event.message.subject);
    }
});
无需公网URL,持久连接实现即时投递。
Python(同步):
python
from agentmail import AgentMail, Subscribe, Subscribed, MessageReceivedEvent

client = AgentMail()
with client.websockets.connect() as socket:
    socket.send_subscribe(Subscribe(inbox_ids=["agent@agentmail.to"]))
    for event in socket:
        if isinstance(event, Subscribed):
            print(f"已订阅: {event.inbox_ids}")
        elif isinstance(event, MessageReceivedEvent):
            print(f"发件人: {event.message.from_}")
            print(f"主题: {event.message.subject}")
            print(f"正文: {event.message.extracted_text}")
Python(异步):
python
from agentmail import AsyncAgentMail, Subscribe, MessageReceivedEvent

client = AsyncAgentMail()
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):
            await process_email(event.message)
TypeScript:
typescript
const socket = await client.websockets.connect();
socket.on("open", () => {
    socket.sendSubscribe({ type: "subscribe", inboxIds: ["agent@agentmail.to"] });
});
socket.on("message", (event) => {
    // 使用event.eventType(而非event.type —— event.type始终为"event")
    if (event.eventType === "message.received") {
        // TypeScript直接使用.from;仅Python需使用.from_(因from为保留关键字)
        console.log("发件人:", event.message.from);
        console.log("主题:", event.message.subject);
    }
});

Webhooks

Webhook

HTTP POST to your endpoint on email events. Requires a public URL.
event_types
is required — you must pick at least one event to subscribe to. Pass an explicit list of every event you want to receive.
python
webhook = client.webhooks.create(
    url="https://your-server.com/webhooks",
    event_types=["message.received", "message.bounced"],
)
邮件事件触发时向您的端点发送HTTP POST请求,需公网URL。
event_types
为必填项——您必须选择至少一个事件进行订阅,传入您希望接收的所有事件的明确列表。
python
webhook = client.webhooks.create(
    url="https://your-server.com/webhooks",
    event_types=["message.received", "message.bounced"],
)

webhook.webhook_id, webhook.secret

webhook.webhook_id, webhook.secret

List, get, delete

列出、获取、删除Webhook

webhooks = client.webhooks.list() client.webhooks.delete(webhook_id=webhook.webhook_id)

Typed webhook event types (listed in the SDK's Literal): `message.received`, `message.sent`, `message.delivered`, `message.bounced`, `message.complained`, `message.rejected`, `domain.verified`.

Runtime-only events — accepted by the API but not in the SDK's typed Literal — include `message.received.spam` and `message.received.blocked`. Pass them as plain strings if you need them. Type checkers will flag them; that's expected.

Always verify webhook signatures before processing. See `references/webhooks.md`.
webhooks = client.webhooks.list() client.webhooks.delete(webhook_id=webhook.webhook_id)

已类型化的Webhook事件类型(SDK的Literal中列出):`message.received`, `message.sent`, `message.delivered`, `message.bounced`, `message.complained`, `message.rejected`, `domain.verified`。

仅运行时支持的事件——API接受但未包含在SDK的类型化Literal中——包括`message.received.spam`和`message.received.blocked`。如需使用请传入纯字符串,类型检查器会标记,此为预期行为。

处理前请始终验证Webhook签名,详见`references/webhooks.md`。

Idempotency

幂等性

Pass
client_id
/
clientId
on create operations to make them safe to retry:
python
from agentmail.inboxes.types import CreateInboxRequest

inbox = client.inboxes.create(
    request=CreateInboxRequest(client_id="my-unique-key"),
)
在创建操作中传入
client_id
/
clientId
可确保操作可安全重试:
python
from agentmail.inboxes.types import CreateInboxRequest

inbox = client.inboxes.create(
    request=CreateInboxRequest(client_id="my-unique-key"),
)

Calling again with the same client_id returns the existing inbox, not a duplicate

使用同一client_id再次调用会返回现有邮箱,不会创建重复项

pod = client.pods.create(client_id="pod-unique-key")
pod = client.pods.create(client_id="pod-unique-key")

pods.create takes flat kwargs; same idempotency behavior

pods.create接受扁平参数,幂等行为相同

undefined
undefined

Error handling

错误处理

Both SDKs raise/throw on 4xx and 5xx responses. On 429 (rate limit), read the
Retry-After
header and use exponential backoff. Both SDKs retry automatically (default: 2 retries).
python
try:
    client.inboxes.messages.send(inbox_id, to="user@example.com", subject="Hi", text="Hello")
except Exception as e:
    print(f"Error: {e}")
    # e.body.message contains details if available
两个SDK在收到4xx和5xx响应时都会抛出异常。收到429(请求超限)响应时,请读取
Retry-After
头并使用指数退避策略。两个SDK均会自动重试(默认:2次)。
python
try:
    client.inboxes.messages.send(inbox_id, to="user@example.com", subject="Hi", text="Hello")
except Exception as e:
    print(f"错误: {e}")
    # 若可用,e.body.message包含详细信息

Python: override retries per call via request_options

Python:通过request_options覆盖单次调用的重试次数

(the AgentMail constructor has no max_retries argument)

(AgentMail构造函数无max_retries参数)

client.inboxes.messages.send( inbox_id, to="user@example.com", subject="Hi", text="Hello", request_options={"max_retries": 5}, )

```typescript
try {
    await client.inboxes.messages.send(inboxId, {
        to: "user@example.com",
        subject: "Hi",
        text: "Hello",
    });
} catch (err) {
    console.error("Error:", err.message);
    // err.statusCode, err.body for details
}

// TypeScript: override retries globally on the client, or per-call via requestOptions
const client = new AgentMailClient({ apiKey: "...", maxRetries: 5 });
client.inboxes.messages.send( inbox_id, to="user@example.com", subject="Hi", text="Hello", request_options={"max_retries": 5}, )

```typescript
try {
    await client.inboxes.messages.send(inboxId, {
        to: "user@example.com",
        subject: "Hi",
        text: "Hello",
    });
} catch (err) {
    console.error("错误:", err.message);
    // err.statusCode, err.body包含详细信息
}

// TypeScript:在客户端全局覆盖重试次数,或通过requestOptions覆盖单次调用
const client = new AgentMailClient({ apiKey: "...", maxRetries: 5 });

IMAP and SMTP

IMAP与SMTP

AgentMail inboxes are accessible via standard IMAP and SMTP protocols, enabling integration with traditional email clients and legacy systems. See https://docs.agentmail.to/imap-smtp for setup details.
AgentMail邮箱可通过标准IMAP和SMTP协议访问,支持与传统邮件客户端及遗留系统集成。设置详情请参考https://docs.agentmail.to/imap-smtp。

Pagination

分页

All list endpoints use cursor-based pagination:
python
response = client.inboxes.messages.list(inbox_id, limit=20)
while response.next_page_token:
    response = client.inboxes.messages.list(
        inbox_id, limit=20, page_token=response.next_page_token
    )
所有列表接口使用基于游标的分页:
python
response = client.inboxes.messages.list(inbox_id, limit=20)
while response.next_page_token:
    response = client.inboxes.messages.list(
        inbox_id, limit=20, page_token=response.next_page_token
    )

Reference files

参考文档

For detailed coverage of specific topics:
  • references/webhooks.md
    -- webhook setup, event types, payload structure, signature verification
  • references/websockets.md
    -- WebSocket connection, sync/async patterns, event handler pattern, subscribe options
  • references/full-api-reference.md
    -- complete endpoint and SDK method table with all parameters
特定主题的详细说明:
  • references/webhooks.md
    -- Webhook设置、事件类型、负载结构、签名验证
  • references/websockets.md
    -- WebSocket连接、同步/异步模式、事件处理器模式、订阅选项
  • references/full-api-reference.md
    -- 完整的端点与SDK方法表,包含所有参数