跳过主要内容
A

dsh-qq-email

altmanwang/dsh-qq-email

用已授权的 agently-cli 账号发送 QQ 邮件:注册 send_qq_email 工具(发送前需用户确认),并对外提供 ctx.qqEmail 服务供其他 DSH 插件调用。

安装

dsh plugin --profile web add github:altmanwang/dsh-qq-email

README

dsh-qq-email

用已授权的 agently-cli 发一封 QQ 邮件。一个包,两种用法:

用法入口给谁用
Cordis 服务 ctx.qqEmailservice.js(exports["."])其他插件:inject: ['qqEmail'] 后直接调用
Agent 工具 send_qq_emailtool.js(exports["./tool"])对话里直接说「给 xxx 发封邮件」

发送逻辑只在服务层实现一次;工具只是参数翻译层。两行插件可以独立开关 (见 cordis.patch.yml)。

功能

  • 对话里发邮件:模型调用 send_qq_email,DSH 弹出确认卡,用户批准后才真正发送。
  • 其他插件发邮件:ctx.qqEmail.send(...);也可以自己管理确认 UX (prepare() → 自己问用户 → commit())。
  • 预检与发送分离:prepare() 只拿确认令牌,不会发信。
  • 默认 fail-closed:没有批准、没有确认入口、没有 confirmedByCaller 都不会发送。

前置条件

  1. Node.js ≥ 22.19(DSH 运行环境自带)。

  2. DSH 0.2.x(见 package.json 的 engines.dsh)。

  3. 本机安装并授权 agently-cli:

    npm install -g @tencent-qqmail/agently-cli
    agently-cli auth login
    agently-cli +me        # 能打印出邮箱地址即授权成功
    

    插件本身不保存、不接触 OAuth 凭据:令牌由 agently-cli 自己管理 (Windows 上是 DPAPI),插件只是以当前进程身份调用这个 CLI。

安装

发布到 npm 后:

dsh plugin --profile web add dsh-qq-email

也可以直接从 GitHub 安装(包内是纯 JS,无构建步骤,不需要 allowBuilds 授权):

dsh plugin --profile web add github:altmanWang/dsh-qq-email

或本地目录(开发时):

dsh plugin --profile web add /绝对路径/plugin/dsh-qq-email

装完重启 dsh web(或刷新页面);在 Web UI 的插件页能看到两行:服务与工具。

使用:在对话里

直接说:

帮我给 alice@qq.com 发一封邮件,主题「项目进度同步」,正文「本周已完成 X,下周计划 Y」;抄送 bob@qq.com。

模型调用 send_qq_email 后会弹出确认卡(发件人 / 收件人 / 抄送 / 密送 / 主题 / 正文预览), 只有点「批准」才会发送。

使用:在其他插件里

// 你的插件入口
export const inject = ['qqEmail']

export function apply(ctx) {
  // 1) 最常用:完整流程。传 agent 上下文时,服务会弹出确认提示,用户批准后才发送。
  const sent = await ctx.qqEmail.send(
    { to: 'alice@example.com', subject: '周报', body: '见附件' },
    { agent, callId, signal },
  )

  // 2) 自己管确认 UX(例如在 IM 频道里问):先预检,用户点头后再提交。
  const pending = await ctx.qqEmail.prepare({ to: 'a@qq.com', subject: 'Hi', body: '你好' })
  // …向用户展示 pending.summary / pending.request,拿到许可…
  const sent2 = await ctx.qqEmail.commit(pending, { signal })

  // 3) 查当前授权账号与额度(默认缓存 60 秒)
  const { email, scopes, rateLimits } = await ctx.qqEmail.account()
}

agent 必须是完整的 DSH Agent 对象(工具里的 exec.agent),只传 { id } 会在 approval 服务内部报错。commit() 自身不做用户确认;只要用了 prepare() + commit(),确认责任就在调用方。

类型

types.d.ts 只包含纯类型声明、不引用任何 @deepseek-ai/*,所以任何 TS 工程都能引用。 它不做 ctx.qqEmail 的模块增强(增强在外部安装形态下可能解析不到 cordis 类型而静默失效), 请在你的插件里自己写三行:

import type { Context } from '@deepseek-ai/cordis'
import type { QqEmailService } from 'dsh-qq-email/types'

declare module '@deepseek-ai/cordis' {
  interface Context { qqEmail: QqEmailService }
}

配置

CLI 入口按以下顺序解析,第一个存在的生效:

  1. 环境变量 DSH_QQ_EMAIL_CLI(指向 .../agently-cli/scripts/run.js 的绝对路径)
  2. 插件 config 的 cliEntry 字段(在 profile patch 里给该行加 config:)
  3. 各平台 npm 全局前缀推导:Windows 的 %APPDATA%\npm、Program Files\nodejs、 %LOCALAPPDATA%\pnpm;POSIX 的 /usr/local、/usr、/opt/homebrew、 ~/.npm-global、nvm 的各 Node 版本前缀
# profile 的 cordis.patch.yml
- id: qq-email-service
  name: dsh-qq-email
  config:
    cliEntry: C:\Users\me\AppData\Roaming\npm\node_modules\@tencent-qqmail\agently-cli\scripts\run.js

确认与安全模型

  • 两道确认:CLI 自身的两阶段(prepare 拿 ctk_* 令牌,commit 才发送)+ DSH 的 approval。工具路径下用户必须在界面上点「批准」;rejected / cancelled / unavailable 一律不发送。
  • 确认前不可变:prepare() 返回的 request 被深度冻结,确认卡里的收件人 / 主题 与实际发送内容来自同一份数据。
  • 正文传输方式:正文通过 argv 内联传给 CLI,因此它可能出现在本机进程命令行里 (同用户可读)。高度敏感的内容请注意这一点;同时 Windows 命令行长度有限, 超长请求会提前报 QQ_EMAIL_ARGS 而不是运行到一半失败。
  • 取消/超时的语义:预检阶段被取消 = 一定没发;发送阶段被取消或超时 = 结果未知, 错误信息会提示先检查「已发送」,不要直接重试。
  • 确认令牌过期:令牌默认 5 分钟,用户思考过久时 send() 会在批准后用同一请求 重新预检一次再发送,内容不变。

限制

  • 只发送,不读信、不回复、不转发、不带附件(需要这些能力请直接用 agently-cli)。
  • 主题按 UTF-8 4 KB 限制(约 1365 个汉字);正文最多 20000 字符。
  • 收件人(to+cc+bcc)最多 50 个;同一地址不能同时出现在 cc 和 bcc。
  • 工具路径必须由用户在 DSH 里确认;无头/自动化场景请用 confirmedByCaller: true 的插件调用路径,并自行负责确认。

错误码

按 error.code 分支,不要匹配文案:

code含义
QQ_EMAIL_ARGS请求不合法(地址、主题字节数、正文、命令行过长等)
QQ_EMAIL_CLI_MISSING找不到 agently-cli,错误信息里带全部候选路径
QQ_EMAIL_CLI_FAILEDCLI 退出非 0 / ok:false / 调用被取消、超时;授权失效与限频会附操作提示
QQ_EMAIL_NOT_CONFIRMED用户没批准 / 没有确认入口 / 缺 confirmedByCaller
QQ_EMAIL_UNEXPECTEDCLI 返回了预期之外的信封(协议变更、只返回预检结果等)

开发与测试

npm test

npm test 是 hermetic 的:用 tests/fixtures/fake-cli.mjs 冒充 agently-cli,覆盖 预检/发送/确认拒绝/空令牌/空信封/取消等路径,不联网、不发信。

真实 CLI 的只读集成测试默认跳过,显式开启:

DSH_QQ_EMAIL_INTEGRATION=1 npm test

注意:DSH 的 Windows 沙箱会禁止被约束进程用管道 spawn 子进程(spawn EPERM), 在沙箱内跑测试时 spawn 类用例会自动跳过——它们真正覆盖的是未约束的 Host/CI 环境。

License

MIT

相关插件