# Changelog

> 完整历史（含详细改动说明）。README 只保留最近几个版本的一句话摘要。

## 中文版

- **0.13.1（2026-09-19）**：**新增**：内置一份公共客户端注册（`15dcd5aa-…`，贡献者 [gurio-wine](https://github.com/gurio-wine) 在 [PR #13](https://github.com/STARDUSTLC666/dsh-email/pull/13) 注册，并授权本项目内置使用，特此致谢）——Outlook / Exchange Online 的 OAuth2 登录**开箱即用**，不再需要每个用户自己注册应用。设置页卡片会显示当前生效的应用 ID：留空即用内置的社区应用，填入自己的 `clientId` 即覆盖（账号级仍可覆盖顶层简写）。**文档**：README 说明内置应用来自谁、代价是什么、如何换成自己的；并说明 token 与签发它的应用 ID 绑定，将来替换内置注册需要这些账号重新登录一次。测试 262 → 264 项。
- **0.13.0（2026-09-18）**：**修复**：①长正文截断会把整段正文丢成空（无断点时硬切，保留正文）；②`email_watch` / 网页弹窗的游标会永久漏报一次超过 `limit` 条的新邮件（改为最旧优先分批、游标只推进到实际返回那批）；③附件索引缓存未绑定 UIDVALIDITY，服务器重编号后可能按旧索引写出错误附件（缓存键并入 uidValidity）。**性能**：10 个工具声明 `timeoutMs`（search/watch 120s，其余 60s）；watch/弹窗轮询只 FETCH 本轮要报的条数（此前每轮最多 FETCH 100 封未读信封）；读信与正文搜索只下载 text/* 分段，不再把整封（含附件）拉下来。**口径**：搜索回退路径明确标注为扫描口径（「本页 N 条（仅扫描最近 X 封）」，不再冒充全文件夹匹配数）。**行为变化**：`email_read` 的 `attachments` 只列可下载的 `disposition=attachment`（内嵌图片不再列出）；回退扫描改为逐封下载文本分段（省流量、往返略增）。测试 237 → 262 项。
- **0.12.0（2026-09-18）**：**新增发送别名**（`senderName` / `authUser` / `authPassword`）：`user` 只作为发件地址与信箱身份，登录名与登录密码可以另填——Gmail / Workspace 的别名发信、以及「登录账号 ≠ From 地址」的 SMTP 中继不再被 `535 Username and Password not accepted` 拒绝，From 也能带显示名。设置页账号卡片新增「发件显示名 / 登录账号 / 登录账号的密码」三栏（与授权码同一套三态：留空保留已存值、清空即删除）。**新增** `email_search` 的 `offset`，命中多于一页时可翻页。**修复与优化**：文件夹 UIDVALIDITY 变化时重建 `email_watch` / 弹窗的增量基线（不再把重编号后的整箱当成新邮件）；搜索的命中复核与结果列表合并为一次 FETCH；`email_attachment` 复用 `email_read` 已解析的 MIME 索引，不再把整封邮件（含附件）重下一遍；`email_folders` 结果缓存 60 秒；网页端新邮件弹窗在标签页不可见时暂停轮询、失败指数退避、皮肤快照降频。**工程**：CI 增加「`lib/` 与 `src/` 不允许漂移」和客户端 bundle 语法检查。测试 237 → 252 项。发送别名的方向来自 [@TianLanDaoRen](https://github.com/TianLanDaoRen) 的 [PR #8](https://github.com/STARDUSTLC666/dsh-email/pull/8)（本实现按 0.11.0 之后的代码重写）。
- **0.11.0（2026-09-18）**：合入 gurio-wine 的设置页四连（[PR #11](https://github.com/STARDUSTLC666/dsh-email/pull/11)–[#14](https://github.com/STARDUSTLC666/dsh-email/pull/14)），并在评审后修掉其中若干问题。**新增**：①多账号卡片编辑器（增删改 / 改名 / 设默认 / 按账号单独测试连接，编辑即保存，不再需要点「保存并应用」）与服务器预设管理（`serverPresets`，自定义服务商端点，不含凭证）；②Outlook / Exchange Online 的 OAuth2 设备码登录（IMAP 与 SMTP 双端，access token 自动刷新，密码认证账号完全不受影响）；③设置面板文案中英双语，跟随宿主 Settings → General 的语言实时切换；④账号可显式钉住 `authKind`（自动 / oauth2 / password），给仍能用应用密码连 Exchange Online 的混合或本地租户留退路。**评审修复**：SMTP 的 OAuth2 认证形状原本一封也发不出去（nodemailer 的 `XOAuth2` 只读 `accessToken`、从不读 `pass`，实测报 `EAUTH`）；保存面板不再无条件抹掉账号手写的 imap/smtp 端点（运行时解析以账号自己的值优先，原行为会把自建服务器账号静默改指预设，无 provider 的账号则直接失去连接信息）；改名保留授权码与高级键，且不允许顶掉同名账号；设置路由增加 Host / Origin / Content-Type 同源校验（此前任意网页都能跨源改设置，DNS rebinding 还能读走含明文授权码的快照）；响应不再回显解析后的账号映射（那是一份含明文密码、前端从不读取的副本）；服务器原始报错经凭据脱敏后才展示（IMAP/SMTP 会回显被拒的认证串，其中含 access token）；删除账号即清理其 token，未提交的保存不清；版本冲突自动重基，而不是拿旧 revision 反复重试。**不内置任何第三方 OAuth2 应用注册**：OAuth2 账号需自带 `clientId`，见下文「Outlook OAuth2」。测试 81 → 237 项。**修复 `email_search`**：QQ 这类服务器会对任意关键词返回同一批无关 UID，现在服务器命中会先用 envelope 复核（subject/from/to/cc），核实不到就回退本地正文扫描，不会再出现「不存在的关键词也匹配 40 条」（[#15](https://github.com/STARDUSTLC666/dsh-email/issues/15)）。
- **0.10.8（2026-09-16）**：合入 GUODnuli 的 [PR #9](https://github.com/STARDUSTLC666/dsh-email/pull/9)，将设置页及新邮件弹窗的文字、边框引用改为官方主题变量，修复深色主题文字不可读；复验官方 Harness 0.1.5-rc.2 和 0.1.6-alpha.1。
- **0.10.7（2026-09-11）**：复验官方 Harness 0.1.5-rc.1，更新整套同载与真实服务验证记录；运行时代码未变。
- **0.10.6（2026-09-10）**：修复单账号设置页授权码留空时，空字符串遮蔽 `DSH_EMAIL_PASSWORD`，导致“测试连接”和保存后工具调用报未配置的问题；显式密码仍优先，多账号不会借用该环境变量。更新设置页工具数量、多账号说明，并补充真实 QQ 邮箱验证结果。
- **0.10.5（2026-09-08）**：补充官方 Harness 0.1.3-alpha.2 的安装、工具注册及 Web 设置接口验证，更新 Node 版本要求，明确 `email_health` 只检查配置；运行时代码与 0.10.4 相同。
- **0.10.4（2026-09-07）**：将 `mailparser` 最低版本提升到 `3.9.22` 并更新锁文件，使用 `html-to-text 10.0.1 → deepmerge-ts 8.0.2` 的修复链处理 [CVE-2026-40345](https://github.com/RebeccaStevens/deepmerge-ts/security/advisories/GHSA-ggr8-5vv4-36mx)。不依赖插件作为下游依赖安装时不生效的根级 `pnpm.overrides`；新增真实依赖链与 HTML 邮件解析回归测试。依赖告警不等于已证实邮件输入可触发该漏洞。
- **0.10.1**：补发制品——已发布的 0.10.0 打包时只含 `email_mark`，本版同时包含 `email_mark` 与 `email_reply`，代码与 0.10.0 的 main 一致。
- **0.10.0**：新增 `email_mark`（已读/未读/星标/移动文件夹，补齐收发闭环的整理侧）与 `email_reply`（回复/回复全部/转发，自动线程头+引文，走发信审批门）；连接池按读/写模式分别管理邮箱打开状态。
- **0.9.1**：修复设置页空主机遮蔽 provider 预设（#3/#6）；IMAP 连接超时不再杀死整个 DSH 进程（#4）；暗色模式输入控件可见（#2）；密码栏提示环境变量 `DSH_EMAIL_PASSWORD` 免明文方案（#5）。
- **0.9.0**：新增 `email_watch` 增量新邮件检查工具（游标式，适合定时提醒）；Web 端新增「鲸鱼娘递信」新邮件弹窗（本地皮肤素材运行时读取 + 内置回退图）。
- **0.8.2**：`since` / `until` 参数描述与其余参数统一为英文，方便多语言 agent 理解。
- **0.8.0/0.8.1**：`email_list` / `email_search` 新增 `since` / `until` 日期范围过滤；新增 `email_health` 账号配置自检；适配 harness 0.1.2（清理已删除的客户端注入声明）。
- **0.6.2**：服务器端搜索补齐 `cc`，搜索范围真正覆盖主题 / 发件人 / 收件人 / 抄送；正文回退扫描也匹配 `to` / `cc`，单封解析失败不中断整批；列表强制 UID 降序「最新在前」；`email_send` 附件参数严格校验。

## English

- **0.13.0 (2026-09-18)**: **Fixes**: (1) long bodies could be truncated to nothing (now hard-cut with the body preserved); (2) the `email_watch` / popup cursor permanently skipped new mail beyond one `limit` batch (now oldest-first batching, cursor only advances over what was actually returned); (3) the attachment index cache ignored UIDVALIDITY, so a renumbered mailbox could download the wrong attachment (cache key now includes uidValidity). **Performance**: all ten tools declare `timeoutMs` (120s for search/watch, 60s otherwise); watch/popup polls FETCH only the rows they report (previously up to 100 unread envelopes per poll); reads and body search download text/* parts only instead of the whole message with its attachments. **Semantics**: the body-scan fallback now labels itself as such ("this page only, scanning the newest N messages") instead of claiming a folder-wide match count. **Behaviour change**: `email_read` now lists only downloadable `disposition=attachment` entries (inline images are no longer listed); the fallback scan fetches per message (fewer bytes, slightly more round trips). Tests 237 → 262.
- **0.12.0 (2026-09-18)**: **send-as alias** (`senderName` / `authUser` / `authPassword`): `user` is now only the From address and the mailbox identity, while the login user and password can differ — Gmail / Workspace aliases and SMTP relays where the login is not the From address no longer fail with `535 Username and Password not accepted`, and the From header can carry a display name. The account card gained three fields (same three-state contract as the authorization code: empty keeps the stored value, clearing deletes the key). **New**: `offset` for `email_search`, so results beyond the first page are reachable. **Fixes and optimisations**: a changed folder UIDVALIDITY re-seeds the `email_watch` / popup baseline instead of reporting the renumbered mailbox as new; search verification and the result rows share one FETCH; `email_attachment` reuses the MIME index `email_read` already parsed instead of downloading the whole message again; `email_folders` is cached for 60s; the web new-mail popup pauses while the tab is hidden, backs off on failures and refreshes its skin snapshot less often. **Engineering**: CI now rejects `lib/` drift against `src/` and syntax-checks the hand-written client bundle. Tests 237 → 252. The send-as direction came from [@TianLanDaoRen](https://github.com/TianLanDaoRen)'s [PR #8](https://github.com/STARDUSTLC666/dsh-email/pull/8) (this implementation is a rewrite on top of 0.11.0).
- **0.11.0 (2026-09-18)**: merge gurio-wine's four settings-page PRs ([#11](https://github.com/STARDUSTLC666/dsh-email/pull/11)–[#14](https://github.com/STARDUSTLC666/dsh-email/pull/14)) with post-review fixes. **Added**: ① visual multi-account card editor (add/edit/delete, rename, set-default, per-account connection test — edits auto-save; no "Save & Apply" button) and server-preset management (`serverPresets`, custom provider endpoints, no credentials); ② OAuth2 device-code login for Outlook / Exchange Online (IMAP and SMTP share one token; automatic refresh; password-auth accounts unaffected); ③ bilingual settings-panel copy that follows the host's Settings → General language in real time; ④ accounts can pin `authKind` (auto / oauth2 / password), giving hybrid or on-premises tenants that still accept app passwords an escape hatch. **Review fixes**: SMTP OAuth2 could never send (nodemailer's `XOAuth2` reads only `accessToken`, never `pass` — confirmed `EAUTH`); saving no longer unconditionally wipes account-level hand-written imap/smtp endpoints (runtime prefers the account's own host; the old behavior silently re-pointed custom-server accounts to presets, and accounts without a provider lost connection info entirely); rename preserves stored auth codes and advanced keys and refuses to overwrite an existing account name; settings routes now enforce Host / Origin / Content-Type same-origin checks (previously any web page could cross-origin-write settings; DNS rebinding could read snapshots containing plaintext auth codes); responses no longer echo the resolved account map (a plaintext-password copy the front end never reads); raw server errors are credential-scrubbed before display (IMAP/SMTP echo rejected auth strings containing access tokens); deleting an account cleans its tokens (uncommitted saves do not); version conflicts auto-rebase instead of retrying with a stale revision. **No third-party OAuth2 app registration is bundled**: OAuth2 accounts must supply their own `clientId` — see "Outlook OAuth2" below. Tests: 81 → 237. **`email_search` fix**: servers like QQ answer any keyword with the same unrelated uid list; hits are now re-verified against the envelopes (subject/from/to/cc) and fall back to the local body scan when none survive, so an impossible keyword no longer "matches" 40 messages ([#15](https://github.com/STARDUSTLC666/dsh-email/issues/15)).
- **0.10.8 (2026-09-16)**: integrate GUODnuli's [PR #9](https://github.com/STARDUSTLC666/dsh-email/pull/9), replacing nonexistent text and border variables in settings and notifications with official theme tokens; revalidate Harness 0.1.5-rc.2 and 0.1.6-alpha.1.
- **0.10.7 (2026-09-11)**: revalidate official Harness 0.1.5-rc.1 and refresh suite co-load and live-service evidence; runtime code is unchanged.
- **0.10.6 (2026-09-10)**: fix an empty authorization-code field shadowing `DSH_EMAIL_PASSWORD` in single-account connection tests and saved settings. Explicit passwords still take precedence; named accounts cannot borrow this environment variable. Refresh the settings tool count, multi-account guidance and real QQ mailbox validation notes.
- **0.10.5 (2026-09-08)**: document installation, tool registration and the Web settings endpoint in official Harness 0.1.3-alpha.2; update Node requirements and clarify that `email_health` checks configuration only. Runtime code is unchanged from 0.10.4.
- **0.10.4 (2026-09-07)**: raise the minimum `mailparser` version to `3.9.22` and update the lockfile to use the patched `html-to-text 10.0.1 → deepmerge-ts 8.0.2` dependency chain for [CVE-2026-40345](https://github.com/RebeccaStevens/deepmerge-ts/security/advisories/GHSA-ggr8-5vv4-36mx). This does not rely on root-only `pnpm.overrides`, which cannot fix consumers installing this plugin as a dependency. Add runtime dependency-chain and HTML-message parsing regression tests. An affected dependency is not proof that mail input can trigger this vulnerability.
- **0.9.0**: new `email_watch` incremental new-mail tool (cursor-based, ideal for scheduled notifications); new "whale-girl courier" new-mail popup in the web UI (local skin artwork read at runtime + built-in fallback).
- **0.8.2**: `since` / `until` parameter descriptions unified to English, consistent with the other parameters, so multilingual agents read them correctly.
- **0.8.0/0.8.1**: `email_list` / `email_search` gained `since` / `until` date-range filters; new `email_health` account-configuration self-check; adapted to harness 0.1.2 (removed the deleted client-injection declaration).
- **0.6.2**: server-side search covers `cc` (subject / sender / recipients / CC); the body fallback scan also matches `to` / `cc` and one malformed message no longer aborts the batch; lists are UID-descending (newest first); `email_send` strictly validates attachment paths.
