himalaya Maildir 自定义关键词读取指南:dovecot-keywords 与 X-Keywords / X-Label 的配置与实现原理
CLI【免费下载链接】himalayaCLI to manage emails项目地址https://gitcode.com/gh_mirrors/hi/himalaya点击查看免费下载himalaya 的 Maildir 后端在 v0.8 引入了maildir.keywords.dovecot与maildir.keywords.header两个按账户配置项用于在读取邮件时把 dovecot、mbsync、OfflineIMAP、mutt、notmuch 等工具写入的自定义非 IANA关键词解析为 flag使envelope list flag NonJunk这类搜索在 Maildir 上与 IMAP、JMAP、Graph 后端行为一致。本文以 cairn/changes/maildir-custom-keywords/delta.md 为骨架结合 proposal.md、tasks.md 与仓库源码说明配置方法、两种关键词约定的差异、读写不对称的边界行为以及 io-maildir 库在其中承担的角色。背景Maildir 上自定义关键词为何静默不可见Maildir 的文件名本身只承载六个标准 IANA 信息位Draft、Flagged、Passed、Replied、Seen、Trashed而 dovecot、mbsync、OfflineIMAP 等工具会把自定义关键词以小写字母 slot 的形式追加在 info-section 中例如NonJunk落在某个小写字母上其含义由一个旁挂文件或正文头部另行定义。此前的 himalaya 读取路径只映射六个标准字母、丢弃其余字符导致envelope list flag NonJunk在 IMAP、JMAP 和 Graph 上都能命中在 Maildir 上却静默匹配为空——即使关键词确实在邮箱里。关键在于共享数据模型一直有能力携带自定义关键词Flag以iana: None保留原始拼写其余每个后端都通过Flag::from_raw把它们读回来见 src/email/flag.rs。Maildir 是唯一一个经由封闭表过滤、把六个标准字母之外的小写 slot 字母全部丢弃的后端。为什么必须显式命名而不是自动推断Maildir 没有一个统一的关键词约定因此无法靠猜测解析slot 字母约定关键词存放在邮箱自己的dovecot-keywords文件中把一个小写字母映射到一个关键词名没有这个 sidecar单独的 slot 字母毫无意义。头部约定关键词内联在正文头部中X-Keywords逗号分隔OfflineIMAP、mbsync 使用或X-Label空格分隔mutt、notmuch 使用。由于猜头部可能发明出不存在的 flag两种机制都必须显式开启并指名opt-in and named。这正是 proposal.md 中所述的核心设计约束并最终固化为 delta.md 中的需求maildir.keywords.dovecotSHALL resolve the lowercase info-section slot letters through the resolved mailboxs owndovecot-keywordsfile, andmaildir.keywords.headerSHALL read keywords fromX-Keywords(comma-separated) orX-Label(space-separated). Both default to off, and with both off the flag set SHALL be exactly the six standard info-section letters as before.配置项maildir.keywords.dovecot 与 maildir.keywords.header两个选项都位于账户的[maildir]配置块之下默认全部关闭。仓库自带的 config.sample.toml 给出了完整示例# The Maildir root, one subdirectory per mailbox below it. #maildir.root ~/Mail/example # Resolve custom keywords through each mailboxs own dovecot-keywords file, # which maps a lowercase info-section letter to a keyword. Off by default, # leaving those letters unread. #maildir.keywords.dovecot true # Read custom keywords from a body header instead: x-keywords is the # comma-separated OfflineIMAP and mbsync convention, x-label the # space-separated mutt and notmuch one. Unset by default, reading neither. #maildir.keywords.header x-keywords #maildir.keywords.header x-label # Reading keywords is not a round trip: no command can name a custom keyword, so # flag set replaces the whole set and drops the ones the message carried.配置语义在源码中的定义如下src/config.rsMaildirKeywordHeaderConfigkebab-case 反序列化两个变体——XKeywords对应配置值x-keywords逗号分隔OfflineIMAP/mbsync 约定与XLabel对应x-label空格分隔mutt/notmuch 约定。它刻意在 himalaya 侧保留一个本地镜像使配置 schema 不依赖任何后端 crate从而在任意 feature 子集下都能编译。MaildirKeywordsConfigdovecot: bool是否通过邮箱自己的dovecot-keywords文件解析小写 slot 字母默认false与header: OptionMaildirKeywordHeaderConfig从哪个正文头部读取未设置则不读取。MaildirConfig.keywords使用#[serde(default)]整个块可省略MaildirKeywordsConfig上带deny_unknown_fields拼错键名会直接报错而不是被静默忽略。生效后两个选项会一路下传到 io-maildir 的内部客户端src/maildir/client.rs 在构建MaildirClient时执行两行赋值inner.dovecot_keywords config.keywords.dovecot; inner.keywords_header config.keywords.header.map(Into::into);本地MaildirKeywordHeaderConfig到 io-maildirKeywordHeader的转换由 src/maildir/client.rs 的From实现完成。由于MaildirClient对外 deref 到内部客户端src/maildir/client.rsCLI 与共享构造路径一次性全部覆盖。解析归属io-maildir 负责存储语义himalaya 只保留配置表面这个改动刻意没有把 Maildir 文件名的解析逻辑搬进 himalaya。原因有二格式归属Maildir 文件名含义属于存储语义按贡献指南应由拥有该格式的库io-maildir决定此前 himalaya 在本地实现的parse_filename_flags与flag_from_char是格式逻辑的重复拷贝存在与库漂移的风险本次被删除。复用的需要neverest 与 replica 工作都需要同一份解析结果不可能从一个躺在 himalaya 里的副本获得。io-maildir 的客户端原本就在 store 时持有dovecot_keywords与keywords_header并予以尊重只是读取路径两者都忽略——这正是它看起来像 himalaya 功能的原因。上游补全了读取半边所有读取路径read_entry、read_entries、read_entries_par、get现在都接收条目来自哪个 Maildir作为参数并返回 flag 已解析好的条目结果挂在MaildirFullEntry::flags上组合过程是一个无 I/O 的MaildirFlags::with_keywords客户端为每次调用加载一次映射表见 tasks.md 的任务清单。himalaya 这边剩下的工作是 src/maildir/backend.rs 里的双向映射/// Maps a shared [Flag] to a [MaildirFlag]; non-IANA keywords go /// through [MaildirFlag::Keyword] for the dovecot-keywords sidecar. fn flag_to_maildir(flag: Flag) - MaildirFlag { match flag.iana() { Some(IanaFlag::Seen) MaildirFlag::Seen, Some(IanaFlag::Answered) MaildirFlag::Replied, Some(IanaFlag::Flagged) MaildirFlag::Flagged, Some(IanaFlag::Draft) MaildirFlag::Draft, Some(IanaFlag::Deleted) MaildirFlag::Trashed, Some(IanaFlag::Forwarded) MaildirFlag::Passed, Some(_) | None MaildirFlag::Keyword(flag.raw().to_string()), } } /// Maps a [MaildirFlag] to a shared [Flag]; the inverse of /// [flag_to_maildir]. fn flag_from_maildir(flag: MaildirFlag) - Flag { match flag { MaildirFlag::Seen Flag::from_iana(IanaFlag::Seen), MaildirFlag::Replied Flag::from_iana(IanaFlag::Answered), MaildirFlag::Flagged Flag::from_iana(IanaFlag::Flagged), MaildirFlag::Draft Flag::from_iana(IanaFlag::Draft), MaildirFlag::Trashed Flag::from_iana(IanaFlag::Deleted), MaildirFlag::Passed Flag::from_iana(IanaFlag::Forwarded), MaildirFlag::Keyword(keyword) Flag::from_raw(keyword), } }读取方向中六个标准位回射到 IANA flagMaildirFlag::Keyword则经Flag::from_raw保留原始拼写进入共享模型写入方向反之非 IANA 关键词统一走MaildirFlag::Keyword交给 sidecar。枚举读取时后端直接从MaildirFullEntry::flags取值而不是再解析一遍文件名src/maildir/backend.rs 等处调用self.read_entries(maildir, entries)后经envelope_from_entry构造信封。读取不是往返flag set 会替换整个集合自定义关键词读取存在一个刻意保留的不对称read parity而非 round trip没有任何命令能指名一个自定义关键词——FlagArg是封闭的四变体ValueEnum在任何后端上都无法通过命令行参数写出一个关键词。因此FlagOp::Set的存储会替换整个 flag 集合并丢弃邮件携带的关键词delta.md 明确a FlagOp::Set store SHALL replace the whole set and drop any keyword the message carried。该行为被如实记录进 config.sample.toml 的注释与 CHANGELOG.md而不是试图修复——因为修它需要先扩大 flag 参数的取值面那是另一个跨后端的独立问题明确列入本次非目标。此外头部路径还有一个细节maildir.keywords.header只读且仅在 store 时追加io-maildir 会在解析头部之前排空旧关键词drain。边界行为sidecar 缺失、不可读或禁用不报错规范特别强调了容错语义delta.md 与 cairn/spec/backends.md 一致A sidecar that is absent, unreadable or disabled SHALL yield no keywords rather than fail the listing, since a mailbox without one is the normal case rather than an error.没有dovecot-keywords文件、文件不可读、或对应选项未开启都是该邮箱没有关键词这一正常情况而不是错误——列目录必须照常成功只是不产出任何关键词。依赖与版本前提io-maildir 0.3 与 [patch.crates-io]两个半边的解析能力都是 io-maildir 尚未发布的成果因此存在明确的版本前提proposal.md 的 Upstream prerequisite 一节读取 API 是 0.3 新增的Cargo.toml因此声明io-maildir { version 0.3, default-features false, optional true }Cargo.toml并暂以[patch.crates-io]块指向本地 checkout待 0.3 发布后移除。另一半是上游仓库中已合并但未打 tag 的改动在 0.2.1 上每个 flag store 背后的条目定位逻辑都会在重命名前丢弃 slot 字母导致一次 flag 操作会剥离它从未触碰的关键词——message read --seen也不例外因为它走同一条标记已读的路径。这也是他拉雅 TUIhimalaya-tui需要通过同一 API 读取条目、需要同步升级的原因。maildirfeature 同时启用io-maildir/client与io-maildir/parser两个子 featureCargo.toml自定义关键词解析正是在 client 子 feature 中提供。验证与测试覆盖落地日志cairn/log/2026-08-16-maildir-custom-keywords.md记录了完整的验证情况himalaya 侧build、fmt、clippy 干净112 个测试通过七个原本在测 io-maildir 的测试随解析逻辑一起上移。上游侧io-maildir 80 个单元测试新增 6 个、15 个集成测试新增 7 个位于tests/keyword_reads.rs及 15 个文档测试通过。himalaya 保留的测试聚焦于双向 flag 映射、信封携带读取到的 flag关键词解析本身归上游测试。三个精简 feature 构建通过——它们专门用来捕获后端 crate 泄漏进配置 schema这类问题而MaildirKeywordHeaderConfig本地镜像正是为此存在。端到端验证该改动作为 pimalaya/himalaya#735 提交对一个一次性 Maildir 的实测中envelope search flag NonJunk从零命中变为一个命中未对真实 dovecot 写入的邮箱做二次验证也未在重构后重跑。小结配置三步走要让 Maildir 上的自定义关键词可被flag name搜索命中只需在账户配置中按所用约定开启对应选项dovecot 系slot 字母 dovecot-keywordssidecarmaildir.keywords.dovecot trueOfflineIMAP / mbsyncX-Keywords逗号分隔maildir.keywords.header x-keywordsmutt / notmuchX-Label空格分隔maildir.keywords.header x-label。两者可同时开启、也可都保持默认关闭此时 flag 集合与旧行为完全一致。需注意这只是一次读取能力写入关键词、以及让flag set保留已有关键词均不在本次范围内。相关文档与源码需求变更 cairn/changes/maildir-custom-keywords/delta.md设计提案 cairn/changes/maildir-custom-keywords/proposal.md任务追踪 cairn/changes/maildir-custom-keywords/tasks.md落地日志 cairn/log/2026-08-16-maildir-custom-keywords.md后端规范Maildir 关键词需求 cairn/spec/backends.md配置定义 src/config.rs配置下发 src/maildir/client.rs双向 flag 映射 src/maildir/backend.rs配置示例 config.sample.toml变更日志 CHANGELOG.md赞分享CLI【免费下载链接】himalayaCLI to manage emails项目地址https://gitcode.com/gh_mirrors/hi/himalaya点击查看免费下载相关推荐pandas 窗口操作Windowing Operations完全指南Rolling / Expanding / EWM 窗口函数与自定义索引器 API 详解pandas 窗口操作Windowing Operations完全指南Rolling / Expanding / EWM 窗口函数与自定义索引器 APICLIAutoGPT 中的 DataForSEO Related Keywords Block语义关键词发现与 SEO 指标提取实战指南AutoGPT 中的 DataForSEO Related Keywords Block语义关键词发现与 SEO 指标提取实战指南 导读 本文基于 relat人工智能AI Agent自主智能体Agent 工作流工作流自动化后端前端Builder.io 可视化CMS集成踩坑实录6个报错的完整排查路径Builder.io 可视化CMS集成踩坑实录6个报错的完整排查路径 启动即白屏控制台闪过的唯一红字是 Missing environment variabCLI上一篇开源项目dnsjava快速指南与常见问题解答下一篇终极指南3步将闲置电视盒子变身高性能ARM服务器创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

Codex 代码智能体实战:从安装配置到 Agent 工作流全解析

Codex 代码智能体实战:从安装配置到 Agent 工作流全解析

1. 从零认识 Codex:它到底能帮你做什么第一次听到 Codex 这个词,很多人会下意识觉得“又是一个命令行里敲敲打打的 AI 工具”,跟自己的日常工作没多大关系。但实际用下来你会发现,它更像是一个能直接读写你项目文件、执行命令、跑…

2026/10/4 9:24:22 阅读更多 →
OpenEMR 8.2.0 发布说明自动化生成:ChangelogGenerator 与 GHSA 安全公告匹配机制解析

OpenEMR 8.2.0 发布说明自动化生成:ChangelogGenerator 与 GHSA 安全公告匹配机制解析

医疗健康后端 【免费下载链接】openemr The most popular open source electronic health records and medical practice management solution. 项目地址: https://gitcode.com/GitHub_Trending/op/openemr 点击查看 免费下载 导读 本文围绕 OpenEMR 发布自动化体…

2026/10/4 9:23:21 阅读更多 →
Nav2 Behaviors 行为服务器深度解析:TimedBehavior 模板、内置行为插件与实战配置

Nav2 Behaviors 行为服务器深度解析:TimedBehavior 模板、内置行为插件与实战配置

机器人ROS自动驾驶 【免费下载链接】navigation2 ROS 2 Navigation Framework and System 项目地址: https://gitcode.com/gh_mirrors/na/navigation2 点击查看 免费下载 本文以 ROS 2 Navigation2 框架中的 nav2_behaviors 包为对象,系统讲解集中式行为…

2026/10/4 9:23:21 阅读更多 →

最新新闻

自动扶梯智能监控系统:AI图像识别与功能安全实战解析

自动扶梯智能监控系统:AI图像识别与功能安全实战解析

扶梯旁边贴满了“请站稳扶好”,但真正能管住乘客行为的,从来不是标语。去年我开始做自动扶梯智能监控系统,第一个要回答的问题是:AI图像识别到底能在这个场景里解决什么。传统机械安全回路能在故障发生后触发制动,却没…

2026/10/4 12:55:24 阅读更多 →
AI产物如何沉淀复用?WorkBuddy资料库实现工作流原生知识固化

AI产物如何沉淀复用?WorkBuddy资料库实现工作流原生知识固化

1. 为什么“AI产物”长期处于“用完即弃”的尴尬状态?“WorkBuddy资料库:AI产物终于能沉淀下来了”——这个标题里藏着一个被无数人默认接受、却从未被系统解决的行业隐痛:我们每天用ChatGPT、Claude、Kimi生成的会议纪要、周报草稿、技术方案…

2026/10/4 12:55:24 阅读更多 →
SolidWorks VBA配合开发:装配引擎原理与鲁棒实现方案

SolidWorks VBA配合开发:装配引擎原理与鲁棒实现方案

1. 项目概述:SolidWorks VBA二次开发中“配合”功能的深度实践困境SolidWorks VBA二次开发配合问题——这七个字背后,藏着至少三类工程师的真实焦灼:机械设计工程师想批量创建装配约束却卡在AddMate3返回-1;自动化产线仿真工程师试…

2026/10/4 12:55:24 阅读更多 →
限定领域与开放领域三元组抽取:技术路线与实战指南

限定领域与开放领域三元组抽取:技术路线与实战指南

做知识图谱的人,八成都被非结构化文本喂数据这件事折磨过。数据库里一堆表格好歹能映射,但扔过来几百篇新闻稿、病历描述、法院文书,你能做的第一件事,就是把里面的实体和关系捞出来,整理成 (头实体, 关系, 尾实体) 这…

2026/10/4 12:55:24 阅读更多 →
AI工程从零到落地:大模型应用开发的核心方法与实战指南

AI工程从零到落地:大模型应用开发的核心方法与实战指南

我刚入行那两年,总被一个问题卡住:AI 项目到底该怎么“认真”地做下去?模型会调参、会写 prompt,可一旦要落地成产品,就发现以前那套零散的技能完全不够用。数据、评测、接口、上下文管理、服务质量、成本控制&#xf…

2026/10/4 12:55:24 阅读更多 →
Fibocom LE270模组SDK开发实战:从环境搭建到量产踩坑记录

Fibocom LE270模组SDK开发实战:从环境搭建到量产踩坑记录

LE270-IN-1D3W6-10 这块 Fibocom 模组,我拿到手第一件事是翻 SDK 文档,而不是急着上电。原因很简单:这类无线通信模组看起来就是一块带天线的板子,实际上固件版本、SDK 版本、驱动和三方库之间的匹配关系非常敏感,任何…

2026/10/4 12:54:24 阅读更多 →

日新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 11:40:45 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 9:43:54 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/3 9:42:36 阅读更多 →