- AI 应用
- 后端
【免费下载链接】botpress
The open-source hub to build & deploy GPT/LLM Agents ⚡️
本指南基于 Botpress 官方 Hub 中的 Email 集成文档(integrations/email/hub.md)及其源码展开,介绍如何通过 IMAP 读取邮件、通过 SMTP 发送邮件,将邮件通道接入 Botpress Agent。读完本文,你将掌握该集成的完整配置方法、四个核心 Action 的调用方式、邮件同步机制的底层原理,以及如何基于源码调试与扩展。
一、集成概览:IMAP 读、SMTP 发
Email 集成是 Botpress 官方提供的邮件通道解决方案,它把两种成熟的互联网邮件协议封装成 Agent 可用的 Action 与 Channel:
- IMAP(Internet Message Access Protocol):负责读取收件箱中的邮件,将新邮件转成 Botpress 消息事件推送给 Agent;
- SMTP(Simple Mail Transfer Protocol):负责发送邮件,让 Agent 可以直接回复用户或主动外发邮件。
从集成定义(integrations/email/integration.definition.ts)可以看出,官方对它的定位是"使用 IMAP 和 SMTP 协议发送和接收电子邮件"(Send and receive emails using IMAP and SMTP protocols),当前版本为0.1.4,归属"营销与邮件"(Marketing & Email)分类。
需要特别注意的一个能力边界:该集成目前不支持 HTML 邮件内容,收发双方都只处理纯文本。这意味着在 Agent 端构造邮件时,应使用纯文本描述内容,避免依赖富文本排版。
二、快速开始:配置文件与参数详解
2.1 官方文档给出的最小配置
在 Botpress Hub 中安装 Email 集成后,需要在集成配置中填写邮箱凭据。官方文档给出了如下示例:
user: yourEmailAccount@gmail.com password: yourAccountPassword host: imap.gmail.com #for gmail2.2 完整的四个配置字段(以源码为准)
对照 integration.definition.ts 中的configuration.schema定义,实际配置共包含4 个必填字段,比文档示例多出smtpHost:
| 字段 | 类型 | 说明 | 示例 |
|---|---|---|---|
user | string | 用于收发邮件的邮箱账号 | example@gmail.com |
password | string | 该邮箱账号的密码或应用专用密码 | yourAccountPassword |
imapHost | string | 要连接的 IMAP 服务器地址 | imap.gmail.com |
smtpHost | string | 要连接的 SMTP 服务器地址 | smtp.gmail.com |
四个字段全部为必填(.required())。对于 Gmail 等主流邮箱服务商,常见的配置组合是imapHost: imap.gmail.com+smtpHost: smtp.gmail.com;对于 QQ 邮箱则为imap.qq.com+smtp.qq.com。若使用企业邮箱或自建邮件服务器,请替换为对应的 IMAP/SMTP 主机名。
提示:多数主流邮箱要求为第三方应用开启 IMAP/SMTP 访问权限并生成"应用专用密码"(App Password),直接使用邮箱登录密码往往会被服务器拒绝。若注册集成时报连接错误,请优先检查这一点。
三、集成生命周期:注册时如何校验配置
Email 集成通过register与unregister两个生命周期钩子管理自身的启停(见 index.ts 与 setup.ts):
- register(注册):设置初始
lastSyncTimestamp状态,并立即发起一次 IMAP 连接(取 1 条消息)来验证配置正确性。若连接失败,会抛出运行时错误"注册集成时发生错误:... 请验证你的配置",从源头拦截错误凭据; - unregister(注销):无额外清理逻辑(源码注释
// nothing to unregister)。
// integrations/email/src/setup.ts 中的校验逻辑(示意) try { await getMessages({ page: 0, perPage: 1 }, props) } catch (thrown: unknown) { throw new sdk.RuntimeError( `An error occured when registering the integration: ${err.message} Verify your configuration.` ) }从 imap.ts 的_getConfig可以看到,IMAP 连接固定使用端口 993 + TLS 加密,并设置了rejectUnauthorized: false(跳过证书校验,便于连接部分自签名证书的邮件服务器):
const _getConfig = function (config: bp.configuration.Configuration) { return { user: config.user, password: config.password, host: config.imapHost, port: 993, tls: true, tlsOptions: { rejectUnauthorized: false }, } }四、四大 Action:Agent 的邮件工具箱
集成对外暴露了 4 个 Action(定义见 integration.definition.ts,实现见 actions.ts),Agent 工作流中可直接调用:
4.1 listEmails:分页列出收件箱邮件
- 输入:
nextToken(可选,页号,从 0 开始); - 输出:
messages(邮件数组)+nextToken(下一页令牌,无更多页时为 undefined); - 实现要点:每页固定50 封(
ELEMENTS_PER_PAGE = 50,见 actions.ts);nextToken不能为负数,否则抛出RuntimeError;仅拉取邮件头(HEADER),不包含正文,适合快速扫描收件箱。
4.2 getEmail:按 ID 获取单封邮件
- 输入:
id(邮件的唯一标识,即 IMAP 服务器返回的message-id); - 输出:完整的
emailSchema字段 +body(邮件正文); - 实现要点:通过 IMAP
search按MESSAGE-ID头搜索邮件(见 imap.ts),找不到时返回 undefined 并抛出"找不到对应 ID 的邮件"错误。注意:搜索使用的 ID 是邮件头中的message-id,并非 IMAP 序号,跨会话稳定。
4.3 syncEmails:增量同步新邮件
- 输入/输出:均为空对象;
- 作用:把"未读过的"邮件作为新消息推送给 Agent,需要周期性调用才能让 Bot 持续收到新邮件;
- 实现要点:这是接收邮件链路上最关键的 Action,下一节详细展开。
4.4 sendEmail:通过 SMTP 发送邮件
- 输入:
to(必填):收件人邮箱;subject(可选):邮件主题;text(可选):邮件正文(纯文本);inReplyTo(可选):要回复的邮件 ID,用于构造回复线程;replyTo(可选):收件人回复时应使用的地址,允许与发件人不同;
- 输出:空对象;
- 实现要点:底层使用
nodemailer创建 transporter 并调用sendMail(见 smtp.ts),from固定为配置中的user,同时把inReplyTo写入邮件的references头以维护线程:
const transporter = nodemailer.createTransport({ host: config.smtpHost, auth: { user: config.user, pass: config.password }, }) await transporter.sendMail({ from: config.user, ...props, references: props.inReplyTo, })五、邮件同步的底层机制:状态、锁与去重
syncEmails是"收件"的核心,其实现逻辑(actions.ts)值得细读,它由三块机制协同完成:
5.1 同步锁:防止并发同步
locking.ts 中的LockHandler利用集成的syncLock状态(见 integration.definition.ts)实现互斥:
const currentlySyncing = await lock.readLock() if (currentlySyncing) throw new sdk.RuntimeError('The bot is still syncing the messages. Try again later.') await lock.setLock(true) // ... 同步逻辑 ... await lock.setLock(false)如果上一次同步尚未结束,再次调用syncEmails会直接报错"Bot 仍在同步消息,请稍后再试",避免两个同步任务同时抢占 IMAP 连接。
5.2 时间戳状态:增量去重
lastSyncTimestamp状态记录了上一次成功同步的时间(integration.definition.ts)。同步时逐封对比邮件日期:
const messageAlreadySeen = message.date && lastSyncTimestamp && new Date(message.date) <= new Date(lastSyncTimestamp.lastSyncTimestamp) if (messageAlreadySeen) continue日期不晚于上次同步时间的邮件视为已处理,直接跳过;同步完成后将当前时间写入状态。这样既避免重复推送,又能在 Bot 重启后从断点继续。
5.3 消息通知链路:从邮件到对话
未被跳过的邮件会进入_notifyNewMessage(actions.ts),完整链路为:
- 用户映射:以发件人邮箱为
email标签,getOrCreateUser创建或复用 Botpress 用户; - 会话映射:以
firstMessageId(取邮件references头中最早的 message-id,否则回退为自身 id)为区分标签,getOrCreateConversation创建或复用会话,同时把subject、to、latestEmail写入会话标签(integration.definition.ts); - 消息落库:
createMessage以纯文本形式把邮件正文(message.body ?? '')写入会话,并打上邮件id标签。
发件人为配置中的user自己的邮件会被直接跳过(if (message.sender === props.ctx.configuration.user) continue),避免把 Bot 自己发出的邮件又当成新消息回灌。
六、Channel 视角:Bot 如何回复邮件
集成定义了default通道(integration.definition.ts,实现见 channels.ts),支持text类型消息。当 Agent 决定回复某封邮件时,通道处理器自动完成"回复拼接":
await smtp.sendNodemailerMail( props.ctx.configuration, { to: props.conversation.tags.to, subject: 'Sent from botpress email integration', text: props.payload.text, inReplyTo: props.conversation.tags.latestEmail, replyTo: props.ctx.configuration.user, }, props.logger )几个值得注意的细节:
- 收件人取自会话标签
to:即原邮件的收件人,若会话缺少该标签会抛出"尝试在没有 'to' 头的情况下发送邮件"错误; inReplyTo使用会话标签latestEmail:即该会话最新一封邮件的 ID,确保回复挂到正确的邮件线程上;replyTo固定为配置中的user:收件人回复时会回到 Bot 的邮箱账号;- 主题固定为 "Sent from botpress email integration":如需自定义主题,应通过
sendEmailAction 而非通道回复。
七、分页算法的实现细节与测试验证
listEmails的分页并非简单偏移量,而是基于 IMAP 序列号区间实现(paging.ts):
export const pageToSpan = (props: PageToSpanProps): Span => { if (props.totalElements <= 0) { throw new sdk.RuntimeError('Could not read the inbox: the number of messages in the inbox is 0') } const lastElementIndex = Math.max(1, props.totalElements - props.page * props.perPage) const firstElementIndex = Math.max(1, lastElementIndex - props.perPage + 1) return { firstElementIndex, lastElementIndex } } export const getNextToken = (props: NextTokenProps): number | undefined => { if (props.firstElementIndex === 1) return undefined return props.page + 1 }其语义为:第 0 页取最新 50 封(收件箱末尾),页码越大越往旧邮件方向翻;当某一页已经覆盖到第 1 封(最旧)邮件时,getNextToken返回undefined,表示没有下一页了。
该算法有配套的单测覆盖(paging.test.ts),包括空收件箱抛错、单封邮件、不足一页、满页、翻页与 token 边界等场景,例如:
test('pageToSpan with full page returns first page', () => { expect(pageToSpan({ page: 0, perPage: 50, totalElements: 300 })).toEqual({ firstElementIndex: 251, lastElementIndex: 300, } satisfies Span) })八、本地开发与调试
该集成位于integrations/email/目录下,package.json提供了完整的开发脚本:
{ "name": "@botpresshub/email", "scripts": { "check:type": "tsc --noEmit", "check:bplint": "bp lint", "build": "bp build", "test": "vitest --run" }, "dependencies": { "@botpress/client": "workspace:*", "@botpress/sdk": "workspace:*", "imap": "^0.8.17", "nodemailer": "^6.7.2" } }- 类型检查:
tsc --noEmit,确认类型定义与.botpress生成代码一致; - 集成规范检查:
bp lint,使用 Botpress CLI 校验集成定义是否符合平台规范; - 单元测试:
vitest --run,目前覆盖分页算法; - 构建:
bp build,产出可部署的集成包。
IMAP 相关错误在源码中均被包装为RuntimeError并附带原因,排查问题时重点关注两类报错:注册阶段的"验证你的配置"(多半是凭据或主机名问题)与同步阶段的"验证集成配置参数"(可能是网络或服务器权限问题)。
九、使用建议与限制总结
| 场景 | 推荐做法 |
|---|---|
| 接收新邮件 | 周期性(如每分钟)调用syncEmails,或在定时任务中触发 |
| 扫描收件箱 | 调用listEmails分页浏览邮件头,配合nextToken翻页 |
| 读取邮件全文 | 用listEmails得到的id调用getEmail获取body |
| 主动发信 | 调用sendEmail,可自定义收件人、主题、正文与回复线程 |
| 会话式回复 | 让 Agent 在邮件会话上下文中回复,走default通道自动挂线程 |
当前版本的能力边界与已知限制包括:
- 不支持 HTML 内容:收发双方均为纯文本;
- IMAP 固定使用 993 端口 + TLS,且跳过证书校验(
rejectUnauthorized: false),在安全性要求极高的内网环境需注意; syncEmails每次同步只处理最新一页(50 封)内的新邮件,超过 50 封的积压需要多次同步才能全部拉取;- 同步为互斥操作,并发调用会直接报错;
- 默认仅处理收件箱(INBOX),不涉及其他 IMAP 文件夹。
参考文件索引
- 官方文档:integrations/email/hub.md
- 集成定义(配置/状态/Action/通道 Schema):integrations/email/integration.definition.ts
- 入口与生命周期注册:integrations/email/src/index.ts、integrations/email/src/setup.ts
- Action 实现(含同步机制):integrations/email/src/actions.ts
- IMAP 实现:integrations/email/src/imap.ts
- SMTP 实现:integrations/email/src/smtp.ts
- 通道处理:integrations/email/src/channels.ts
- 同步锁与分页:integrations/email/src/locking.ts、integrations/email/src/paging.ts
- 分页单测:integrations/email/src/paging.test.ts
- AI 应用
- 后端
【免费下载链接】botpress
The open-source hub to build & deploy GPT/LLM Agents ⚡️
相关推荐
Agent Zero Email Integration 插件:邮件收件箱轮询、智能路由分发与 SMTP 线程化回复的实现机制
Agent Zero Email Integration 插件:邮件收件箱轮询、智能路由分发与 SMTP 线程化回复的实现机制 本文基于 Agent Zero
人工智能大模型AI AgentAgent 框架自主智能体多智能体工具调用MCP 服务浏览器控制OpenClaw Mastery Day 6 实战:用 imap-smtp-email 技能驯服 Gmail 收件箱(IMAP 只读 + 邮件分诊 + 提示注入防护)
OpenClaw Mastery Day 6 实战:用 imap smtp email 技能驯服 Gmail 收件箱(IMAP 只读 + 邮件分诊 + 提示注入
文档教程人工智能大模型OpenClaw Mastery Day 6:用 imap-smtp-email 技能驯服收件箱——IMAP 只读接入、邮件分诊与提示注入防护
OpenClaw Mastery Day 6:用 imap smtp email 技能驯服收件箱——IMAP 只读接入、邮件分诊与提示注入防护 本篇文章是 aw
文档教程人工智能大模型
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考