dsh-mail:为 DSH 配专属邮箱,邮件即会话入口

前言

在 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)的邮件丢弃。

会话与线程

回复判定双保险:

  1. 优先 In-Reply-To / References 指向我方 Message-ID;
  2. 主题中的 [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

两者不发信、不写状态、不标记已读。

典型用法

  1. 配置 IMAP/SMTP 与 allowFrom,设置 workspaceDir,重启 DSH 确认插件 active。
  2. 从白名单地址向 agent 邮箱发一封新邮件,主题与正文即首轮提示;收到受理回执后,记下其中的会话号 [dsh-xxxx]。
  3. 在同一邮件线程回复(或保留主题标签),内容会续接该会话;若该会话正在跑轮次且 interruptSameThread 为 true,新回信会打断当前轮次。
  4. 轮次结束后会收到结果邮件(纯文本,受 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/ 脚本在启用前做只读自检。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜