前言¶
在 DSH 上跑 agent 时,常见入口是本地 Web 或 IDE 侧栏:人要盯着界面、会话也绑在同一台机器的前台进程里。若你希望「发一封邮件就能开一轮任务、回信自动续接上下文」,又不想给机器开公网端口或挂回调 URL,就需要一条纯出站的邮件通道。
下面介绍社区插件 dsh-mail(维护者 secondlgn):给一台机器绑定一个专属邮箱,IMAP 轮询收信、SMTP 发信答复;回复判定靠信头与主题标签,长任务还可被同线程回信打断。插件归类为 客户端,当前 GitHub 星标为 0;设计取舍见仓库 docs/design-spec.md。
这是什么¶
dsh-mail 是 DSH 的 Host 插件(ESM),同时自带 bundle 补丁 cordis.patch.yml,往 profile 里插入插件行。一句话定位:一台机器一个专属邮箱,邮件即会话,回复即续接上下文,答复自动回信。
与「Webhook + 公网服务」类集成不同,它强调:
- 纯出站:机器不需要公网 IP,不开放入站端口,没有回调地址。
- 准入靠白名单:只认
From精确地址,其余丢弃且不发回执。 - 零运行时依赖:IMAP/SMTP 与 MIME 解析均在包内实现,仅使用 Node 内置模块(仓库
package.json要求 Node>=22.0.0)。
核心功能¶
以下能力在 README 中标注为已实现,并在离线仿真中验证。
收发与准入¶
- IMAP 轮询收信(支持
IDLE,不可用时按pollIntervalMs轮询);SMTP 发信,可选回写 Sent 文件夹。 allowFrom白名单:为空时任何人都无法驱动该机器(安全默认,不是 bug)。- 循环邮件抑制;超过
maxMessageBytes(默认 32 MiB)的邮件丢弃。
会话与线程¶
回复判定双保险:
- 优先
In-Reply-To/References指向我方 Message-ID; - 主题中的
[dsh-xxxx]标签(前缀由tagPrefix配置,默认[dsh-)兜底。
都不命中则新建会话。Message-ID 已处理完毕的重复信会被丢弃。
回执、结果与打断¶
| 邮件 | 时机 | 内容概要 |
|---|---|---|
| 受理回执 | 通过准入后立即 | 含回执号与会话号,便于后续续接 |
| 结果回信 | 轮次正常结束 | 该轮助手文本;interrupted / forked 不发结果 |
interruptSameThread 默认为 true:仅当回复属于正在运行的那个会话时才打断;实现为「先 queue 再 cancel」,让新提示接管当前轮次。
附件与状态¶
- 附件可落盘到
<workspace>/.dsh-mail/attachments(受attachments.*限制)。 - 状态目录默认
<DSH_HOME>/mail,含messages.json、threads.json、cursor.json;写入原子化,崩溃时可按recovery(默认rerun)重放未完成信。
尚未实现(README 约定为后续阶段)¶
基于 plan todo 的阶段汇报、权限清单与超范围询问。
界面配置¶
仓库含浏览器侧 lib/client.js,但 README 明确:目前不要指望 Web 侧「邮件通道」卡片能编辑配置——运行时 schemastery 与 .volatile() 不兼容会导致插件行起不来。在此之前请直接改 profile 的 cordis.patch.yml,改完重启 DSH。
安装与启用¶
插件是标准 DSH Host 插件包,安装方式以 README 为准:在 profile 目录($DSH_HOME/profiles/<name>/)配置依赖与 bundle,并用补丁覆盖 dsh-mail 行的完整 config(补丁会整体替换该行 config,不能只写增量)。
1. 获取插件源码¶
README 给出的方式是从 GitHub 克隆仓库(路径按本机实际填写):
git clone https://github.com/secondlgn/dsh-mail
2. 修改 profile 的 package.json¶
在 dependencies 中指向本地路径或 GitHub 源,并在 dsh.profile.bundles 中加入 dsh-mail(否则自带 bundle 补丁不会插入):
// <profile>/package.json
{
"dependencies": {
"dsh-mail": "file:C:/path/to/dsh-mail",
// "dsh-mail": "github:secondlgn/dsh-mail"
},
"dsh": {
"profile": {
"bundles": ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app", "dsh-mail"]
}
}
}
3. 在 cordis.patch.yml 中写全配置¶
不能在 profile 补丁里为条目写 name:(会被静默忽略,插件永不加载);只能按 id: dsh-mail 覆盖配置。密码用 passwordEnv(默认 DSH_MAIL_PASSWORD),不要写进 YAML。
# <profile>/cordis.patch.yml
- id: dsh-mail
config:
enabled: true
imap:
host: imap.example.com
port: 993
user: agent@example.com
passwordEnv: DSH_MAIL_PASSWORD
smtp:
host: smtp.example.com
port: 465
user: agent@example.com
allowFrom:
- you@example.com
workspaceDir: C:/work
workspaceDir 决定邮箱会话的工作目录,每台机器不同,须为真实存在的绝对路径;留空则用当前工作目录。
4. 验证¶
重启 DSH 后,插件行应以 include:dsh-mail 出现且状态为 active。若未出现,依次检查:bundles 是否含 dsh-mail、补丁是否误写 name:、package.json 是否合法 JSON。
网易邮箱(163/126/yeah)¶
需在邮箱设置开启 IMAP/SMTP 并使用授权码。插件会在 CAPABILITY 含 ID 时自动发 RFC 2971 的 ID 命令;Sent 文件夹通过 \Sent 识别,无需手工配 sentMailbox。参考:
- id: dsh-mail
config:
enabled: true
imap:
host: imap.163.com
port: 993
user: you@163.com
passwordEnv: DSH_MAIL_PASSWORD
smtp:
host: smtp.163.com
port: 465
user: you@163.com
passwordEnv: DSH_MAIL_PASSWORD
allowFrom: [you@163.com]
上线前只读自检¶
在仓库根目录、且环境变量 DSH_MAIL_PASSWORD 已设置时:
node tools/mail-probe.mjs you@163.com
node tools/mail-rehearsal.mjs you@163.com
两者不发信、不写状态、不标记已读。
典型用法¶
- 配置 IMAP/SMTP 与
allowFrom,设置workspaceDir,重启 DSH 确认插件active。 - 从白名单地址向 agent 邮箱发一封新邮件,主题与正文即首轮提示;收到受理回执后,记下其中的会话号
[dsh-xxxx]。 - 在同一邮件线程回复(或保留主题标签),内容会续接该会话;若该会话正在跑轮次且
interruptSameThread为 true,新回信会打断当前轮次。 - 轮次结束后会收到结果邮件(纯文本,受
maxResultChars等限制);入站附件在开启时落盘到工作区.dsh-mail/attachments。
入站内容会包一层「邮件模式」元信息再送入模型(说明输出纯文本、控制行宽等),详见 README「邮件模式提示」一节。
常用配置项(节选)¶
完整表格见 GitHub README。节选与日常相关的项:
| 键 | 默认 | 说明 |
|---|---|---|
enabled |
true |
关闭后不建连 |
allowFrom |
[] |
允许驱动 agent 的发件人(精确匹配) |
imap.pollIntervalMs |
20000 |
轮询间隔(有效下限 2000) |
sendReceipt / sendResult |
true |
受理回执 / 结果回信 |
interruptSameThread |
true |
同线程回复打断当前轮次 |
agentPreset |
'' |
邮箱会话使用的 agent 预设,空则用 profile 默认 |
stateDir |
<DSH_HOME>/mail |
插件状态目录 |
适用场景与注意¶
适合谁:需要在不暴露入站端口的前提下,用手机或任意邮件客户端远程驱动某台机器上的 DSH agent;希望「邮件线程 = 会话线程」,并依赖回执号与 [dsh-xxxx] 标签续接上下文。
务必知晓:
- 插件以当前 DSH 进程权限运行;
allowFrom相当于远程执行入口,安装前应阅读源码与许可证(MIT),并只信任白名单地址。 - 社区目录 skillhub.cn 与 DeepSeek / 幻方无官方从属关系;DSH 生态理念是「一切皆插件」,本文事实来源以仓库 README 与
package.json(当前版本 0.1.0)为准。 - 投递语义为至少一次:进程在「已投递」与「记为完成」之间崩溃可能重放,README 认为重复回答比漏信更可接受。
结尾¶
dsh-mail 把「专属邮箱」做成 DSH 的会话通道:纯出站 IMAP/SMTP、白名单准入、信头与主题双保险续接、同线程打断与自动回执/结果信,且无额外 npm 运行时依赖。若你的部署模型是「一台机器一个 agent 邮箱」,可按 profile + cordis.patch.yml 方式接入,并用 tools/ 脚本在启用前做只读自检。