AgentMail — AI代理的电子邮件服务
AgentMail 为 AI 代理提供真实的电子邮件地址(@theagentmail.net),并通过 REST API 进行管理。代理可以发送和接收邮件、注册各类服务(如 GitHub、AWS、Slack 等),并获取验证码。Karma 系统可防止垃圾邮件,维护共享域名的高信誉。
基础 URL:https://api.theagentmail.net
适用场景
- AI 代理需要真实的收件箱/发件箱,用于服务注册、验证码接收或事务性通信。
- 需要创建 AgentMail 账户、发送消息、读取收件箱内容或注册入站 Webhook。
- 需要监控 Karma 用量或通过邮件事件驱动自动化流程。
快速入门
所有请求都需要在请求头中添加 Authorization: Bearer am_...(API 密钥来自仪表盘)。
创建电子邮件账户(消耗 -10 Karma)
curl -X POST https://api.theagentmail.net/v1/accounts \
-H "Authorization: Bearer am_..." \
-H "Content-Type: application/json" \
-d '{"address": "[email protected]"}'
响应:{"data": {"id": "...", "address": "[email protected]", "displayName": null, "createdAt": 123}}
发送邮件(消耗 -1 Karma)
curl -X POST https://api.theagentmail.net/v1/accounts/{accountId}/messages \
-H "Authorization: Bearer am_..." \
-H "Content-Type: application/json" \
-d '{
"to": ["[email protected]"],
"subject": "来自我的代理的问候",
"text": "纯文本内容",
"html": "<p>可选的 HTML 内容</p>"
}'
可选字段:cc、bcc(字符串数组)、inReplyTo、references(用于邮件线程的字符串)、attachments(数组,每项为 {filename, contentType, content},其中 content 为 base64 编码)。
读取收件箱
# 列出邮件
curl https://api.theagentmail.net/v1/accounts/{accountId}/messages \
-H "Authorization: Bearer am_..."
# 获取完整邮件(包含正文和附件)
curl https://api.theagentmail.net/v1/accounts/{accountId}/messages/{messageId} \
-H "Authorization: Bearer am_..."
检查 Karma
curl https://api.theagentmail.net/v1/karma \
-H "Authorization: Bearer am_..."
响应:{"data": {"balance": 90, "events": [...]}}
注册 Webhook(实时入站)
curl -X POST https://api.theagentmail.net/v1/accounts/{accountId}/webhooks \
-H "Authorization: Bearer am_..." \
-H "Content-Type: application/json" \
-d '{"url": "https://my-agent.example.com/inbox"}'
Webhook 回调包含两个安全头:
X-AgentMail-Signature-- 使用 Webhook 密钥对请求体进行 HMAC-SHA256 十六进制摘要签名X-AgentMail-Timestamp-- 回调发送时的毫秒级时间戳
验证签名并拒绝时间戳超过 5 分钟的请求,以防止重放攻击:
import { createHmac } from "crypto";
const verifyWebhook = (body: string, signature: string, timestamp: string, secret: string) => {
if (Date.now() - Number(timestamp) > 5 * 60 * 1000) return false;
return createHmac("sha256", secret).update(body).digest("hex") === signature;
};
下载附件
curl https://api.theagentmail.net/v1/accounts/{accountId}/messages/{messageId}/attachments/{attachmentId} \
-H "Authorization: Bearer am_..."
返回:{"data": {"url": "https://signed-download-url..."}}
完整 API 参考
| 方法 | 路径 | 描述 | Karma |
|---|---|---|---|
| POST | /v1/accounts | 创建电子邮件账户 | -10 |
| GET | /v1/accounts | 列出所有账户 | |
| GET | /v1/accounts/:id | 获取账户详情 | |
| DELETE | /v1/accounts/:id | 删除账户 | +10 |
| POST | /v1/accounts/:id/messages | 发送邮件 | -1 |
| GET | /v1/accounts/:id/messages | 列出邮件 | |
| GET | /v1/accounts/:id/messages/:msgId | 获取完整邮件 | |
| GET | /v1/accounts/:id/messages/:msgId/attachments/:attId | 获取附件 URL | |
| POST | /v1/accounts/:id/webhooks | 注册 Webhook | |
| GET | /v1/accounts/:id/webhooks | 列出 Webhook | |
| DELETE | /v1/accounts/:id/webhooks/:whId | 删除 Webhook | |
| GET | /v1/karma | 获取余额及事件 |
Karma 系统
每个操作都有对应的 Karma 消耗或奖励:
| 事件 | Karma | 原因 |
|---|---|---|
money_paid | +100 | 购买积分 |
email_received | +2 | 收到来自可信域名的回复 |
account_deleted | +10 | 删除地址时退还 Karma |
email_sent | -1 | 发送邮件消耗 Karma |
account_created | -10 | 创建地址消耗 Karma |
重要规则:
- 仅当收到来自可信提供商(Gmail、Outlook、Yahoo、iCloud、ProtonMail、Fastmail、Hey 等)的入站邮件时,才奖励 Karma。来自未知/一次性域名的邮件不会获得奖励。
- 在每个发件人回复之前,仅首次来信会获得 Karma。如果发件人 X 连续发送 5 封邮件而你未回复,只有第一封能获得 Karma。回复 X 后,来自 X 的下封邮件将再次获得 Karma。
- 删除账户会退还创建时消耗的 10 Karma。
当 Karma 降至 0 时,发送邮件和创建账户的请求将返回 HTTP 402。在执行消耗 Karma 的操作前,请始终检查余额。
TypeScript SDK
import { createClient } from "@agentmail/sdk";
const mail = createClient({ apiKey: "am_..." });
// 创建账户
const account = await mail.accounts.create({
address: "[email protected]",
});
// 发送邮件
await mail.messages.send(account.id, {
to: ["[email protected]"],
subject: "你好",
text: "由 AI 代理发送。",
});
// 读取收件箱
const messages = await mail.messages.list(account.id);
const detail = await mail.messages.get(account.id, messages[0].id);
// 附件
const att = await mail.attachments.getUrl(accountId, messageId, attachmentId);
// att.url 是一个签名下载 URL
// Webhook
await mail.webhooks.create(account.id, {
url: "https://my-agent.example.com/inbox",
});
// Karma
const karma = await mail.karma.getBalance();
console.log(karma.balance);
错误处理
import { AgentMailError } from "@agentmail/sdk";
try {
await mail.messages.send(accountId, { to: ["[email protected]"], subject: "Hi", text: "Hey" });
} catch (e) {
if (e instanceof AgentMailError) {
console.log(e.status); // 402, 404, 401 等
console.log(e.code); // "INSUFFICIENT_KARMA", "NOT_FOUND" 等
console.log(e.message);
}
}
常见模式
注册服务并读取验证邮件
const account = await mail.accounts.create({
address: "[email protected]",
});
// 使用该地址进行服务注册(浏览器自动化、API 等)
// 轮询验证邮件
for (let i = 0; i < 30; i++) {
const messages = await mail.messages.list(account.id);
const verification = messages.find(m =>
m.subject.toLowerCase().includes("verify") ||
m.subject.toLowerCase().includes("confirm")
);
if (verification) {
const detail = await mail.messages.get(account.id, verification.id);
// 从 detail.bodyText 或 detail.bodyHtml 中解析验证链接/验证码
break;
}
await new Promise(r => setTimeout(r, 2000));
}
发送邮件并等待回复
const sent = await mail.messages.send(account.id, {
to: ["[email protected]"],
subject: "关于订单 #12345 的咨询",
text: "您能查看一下状态吗?",
});
for (let i = 0; i < 60; i++) {
const messages = await mail.messages.list(account.id);
const reply = messages.find(m =>
m.direction === "inbound" && m.timestamp > sent.timestamp
);
if (reply) {
const detail = await mail.messages.get(account.id, reply.id);
// 处理回复
break;
}
await new Promise(r => setTimeout(r, 5000));
}
类型定义
type Account = { id: string; address: string; displayName: string | null; createdAt: number };
type Message = { id: string; from: string; to: string[]; subject: string; direction: "inbound" | "outbound"; status: string; timestamp: number };
type MessageDetail = Message & { cc: string[] | null; bcc: string[] | null; bodyText: string | null; bodyHtml: string | null; inReplyTo: string | null; references: string | null; attachments: AttachmentMeta[] };
type AttachmentMeta = { id: string; filename: string; contentType: string; size: number };
type KarmaBalance = { balance: number; events: KarmaEvent[] };
type KarmaEvent = { id: string; type: string; amount: number; timestamp: number; metadata?: Record<string, unknown> };
限制
- 仅当任务明确符合上述范围时使用此技能。
- 不要将输出视为环境特定验证、测试或专家评审的替代方案。
- 如果缺少必要的输入、权限、安全边界或成功标准,请停下来并要求澄清。