在 macOS 终端中集成 Himalaya、Khard 与 FZF,打造高效邮件工作流
博主当前使用 Outlook 管理邮件。在习惯了使用 Vim/Neovim 支持“多模态”的文本编辑器之后,再使用其他任何仅支持“插入”状态的文本编辑器,都不免会觉得低效。
有曾设想过把 Vim 搬进 Outloook 但没有找到优良的实现。于是反其道而行之,既然无法把多模态编辑器搬进邮件客户端,那么干脆在终端寻找和配置一个新的邮件客户端算了,当然,最好可以使用外置的 Vim/Neovim 文本编辑器。
对于许多开发者和终端爱好者来说,尽可能地停留在命令行界面中完成工作是一种追求,这不仅关乎效率,也关乎一种专注和沉浸的体验。邮件处理是日常工作中不可或缺的一环,而通过终端管理邮件,可以极大地减少上下文切换,让我们更专注于核心任务。
本文将详细介绍如何在 macOS 环境下,将终端邮件客户端 himalaya
、联系人管理工具 khard
和模糊搜索神器 fzf
完美结合,并借助 grep
和 awk
这两个强大的文本处理工具,打造一个完全由键盘驱动、高效流畅的邮件发送工作流。
准备工作
在开始之前,请确保你已经安装了 Homebrew,这是 macOS 上最方便的包管理工具。我们将使用它来安装所有必要的软件。
# 如果尚未安装 Homebrew,请先执行此命令
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# 安装所有核心工具
brew install himalaya khard fzf grep awk
Part 1: 核心工具解析
在我们将所有工具整合起来之前,首先需要理解每个工具的独立功能和基本用法。
1. himalaya
- 现代化的终端邮件客户端
himalaya
是一个用 Rust 编写的命令行邮件客户端,它的设计目标是快速、安全且易于配置。它支持 IMAP 和 SMTP 协议,可以连接到几乎所有的邮件服务商(如 Gmail, Outlook, ProtonMail 等)。
基本配置
首次运行 himalaya
命令,向导会自动生成一个配置文件,位于 ~/Library/Application Support/himalaya/config.toml
这个路径下。为中心化管理配置文件,建议将其转移至 ~/.config/himalaya/config.toml
这个位置。无需任何额外设置,位于这两个位置的配置文件都可以被自动读取到。
[accounts.Twine]
default = true
email = "alowree@twineintl.com"
display-name = "Alowree Xu - Twine"
downloads-dir = "/Users/alowree/Downloads"
signature = "Best regards, Alowree\n---\nwww.soundfreaq.com\nSoundfreaq® is a registered trademark of Twine.\nTwine Company Limited\nUnit 1506, Workingport Comm. Bldg., 3 Hau Fook Street, Tsim Sha Tsui, Kowloon, Hong Kong"
signature-delim = "\n"
backend.type = "imap"
backend.host = "twineintlcom.securemail.hk"
backend.port = 993
backend.login = "alowree@twineintl.com"
backend.encryption.type = "tls"
backend.auth.type = "password"
backend.auth.cmd = "security find-generic-password -w -a alowree@twineintl.com -s himalaya-imap"
message.send.backend.type = "smtp"
message.send.backend.host = "ud.1025.hk"
message.send.backend.port = 465
message.send.backend.login = "alowree@twineintl.com"
message.send.backend.encryption.type = "tls"
message.send.backend.auth.type = "password"
message.send.backend.auth.cmd = "security find-generic-password -w -a alowree@twineintl.com -s himalaya-smtp"
基本用法:
列出邮件:
sh# 列出收件箱(INBOX)中的最新 10 封邮件 himalaya envelope list
阅读邮件:
sh# 读取指定 ID 的邮件(ID 可以从 list 命令中获取) himalaya message read <EMAIL_ID>
撰写邮件:
sh# 打开默认编辑器(如 Vim 或 Neovim)撰写新邮件 himalaya message write
根据配置文件,终端会使用 Neovim 打开一个邮件模板,格式如下:
mdFrom: Alowree Xu - Twine <alowree@twineintl.com> To: Subject: Best regards, Alowree --- www.soundfreaq.com Soundfreaq® is a registered trademark of Twine. Twine Company Limited Unit 1506, Workingport Comm. Bldg., 3 Hau Fook Street, Tsim Sha Tsui, Kowloon, Hong Kong
用例: 假设你需要快速回复一封工作邮件。你可以通过
himalaya envelope list
找到邮件 ID,然后用himalaya message reply <EMAIL_ID>
直接在终端中完成回复,整个过程无需打开任何图形界面的邮件 App。
2. khard
- 你的命令行通讯录
khard
是一个用于创建、编辑和搜索 CardDAV 联系人的命令行工具。这意味着它可以与你的 iCloud、Google Contacts 或其他支持 CardDAV 的服务同步联系人。
基本配置:
创建 ~/.config/khard/khard.conf
配置文件如下:
[addressbooks]
[[contacts]]
path = ~/.contacts
[general]
editor = nvim
merge_editor = vimdiff
[contact]
show_all_custom_fields = true
show_custom_fields = true
show_hidden_fields = true
display = first_name
group_by_addressbook = false
reverse_order = false
search_in_source_files = true
sort = last_name
show_uids = false
vcard_extension = .vcf
preferred_vcard_version = 3.0
在上面配置中,我们指定了联系人卡片的保存位置,并且在增添、编辑联系人时,指定了使用 Neovim 作为文本编辑器。
基本用法:
添加新的联系人:
shkhard add
Neovim 此时会打开一个联系人模板,你可以选择输入、保存,或者不保存退出而自动丢弃。
列出所有联系人:
shkhard list
输出通常是
姓名 <邮箱地址>
的格式。显示联系人详情:
sh# 使用姓名或 UID 进行搜索 khard show "张三"
查找联系人邮箱:
shkhard email "张三"
真实世界用例: 你需要给同事“李四”发送邮件,但忘记了他的完整邮箱地址。只需在终端输入 khard email "李四"
,就能立刻获得他的邮箱地址,可以直接复制粘贴使用。
3. fzf
- 无处不在的模糊搜索神器
fzf
(fuzzy finder) 是一个通用的命令行模糊搜索工具。它从标准输入(stdin)读取文本列表,然后提供一个交互式的界面让用户进行筛选,最后将被选中的那一行输出到标准输出(stdout)。
基本用法:
在历史命令中搜索:
shhistory | fzf
这会弹出一个可交互的窗口,你可以输入任何相关的词语来快速找到并执行之前用过的命令。
切换 Git 分支:
shgit branch | fzf | xargs git checkout
真实世界用例:fzf
的强大之处在于它可以与任何产生列表输出的命令结合。当你面对成百上千行日志、文件列表或历史记录时,fzf
可以让你在几秒钟内定位到你需要的那一项。
4. grep
和 awk
- 文本处理的双雄
这两个是 Unix/Linux 世界的经典工具,用于处理文本流,是自动化脚本的基石。
grep
(Global Regular Expression Print):grep
用于在文本中搜索匹配特定模式(正则表达式)的行。真实世界用例: 你想在邮件列表中快速找到所有来自
boss@company.com
的邮件。shhimalaya list | grep "boss@company.com"
awk
:awk
是一个强大的文本扫描和处理语言。它逐行读取输入,并能根据指定的分隔符将每一行分割成多个字段($1
,$2
, ...),然后对这些字段进行操作。真实世界用例: 假设
khard list
的输出是张三 <zhangsan@example.com>
。我们只想要尖括号里的邮箱地址。shecho "张三 <zhangsan@example.com>" | awk -F'[<>]' '{print $2}'
这里,
-F'[<>]'
设置了分隔符为<
或>
,awk
会将这行分割成三个字段:"张三 "
、"zhangsan@example.com"
和""
。{print $2}
则打印出第二个字段,也就是我们想要的邮箱地址。
Part 2: 终极整合:compose_with_khard
了解了每个工具的功能后,我们现在的目标是:在执行 himalaya compose
命令时,不再手动输入收件人的邮箱地址,而是从 khard
的联系人列表中通过 fzf
模糊搜索并自动填充。
我们将通过在 ~/.zshrc
(或 ~/.bashrc
) 文件中定义一个 shell 函数来实现这个工作流。
1. 用户工作流(从用户视角)
整合完成后,你的邮件发送流程将变成这样:
- 在终端中输入
compose_with_khard
并按回车。 - 屏幕会提示你选择“To”收件人,并弹出一个
fzf
搜索框。你可以用TAB
键选择多个联系人。 - 选择完毕后按回车,屏幕会再次提示你选择“CC”收件人(如果不需要可以直接按
ESC
取消)。 - 最后,终端会提示你输入邮件主题。
- 输入主题并按回车后,你配置的默认文本编辑器会自动打开,邮件的收件人、抄送和主题都已经为你填好了。
整个过程行云流水,双手无需离开键盘。
2. 代码深度解析
请将以下函数添加到你的 ~/.zshrc
文件末尾,然后执行 source ~/.zshrc
使其生效。
# ~/.zshrc
select_khard_emails () {
khard email --parsable | \
grep -v "searching for 'ALL'..." | \
fzf --multi --preview 'khard show {3}' --preview-window=right:60% \
--header "Select recipients (Tab to select multiple)" | \
awk '{print $1}'
}
compose_with_khard() {
echo "Selecting 'To' recipients..."
local to_emails
to_emails=$(select_khard_emails)
local to_headers=()
if [ -n "$to_emails" ]; then
# Join the emails with a comma for a single 'To:' header
local to_list
to_list=$(echo "$to_emails" | paste -sd, -)
to_headers=(--header "To:$to_list")
fi
echo "Selecting 'CC' recipients (optional)..."
local cc_emails
cc_emails=$(select_khard_emails)
local cc_headers=()
if [ -n "$cc_emails" ]; then
# Join the emails with a comma for a single 'Cc:' header
local cc_list
cc_list=$(echo "$cc_emails" | paste -sd, -)
cc_headers=(--header "Cc:$cc_list")
fi
echo "Enter Subject: "
read SUBJECT
himalaya message write \
"${to_headers[@]}" \
"${cc_headers[@]}" \
--header "Subject:$SUBJECT"
}
这段代码定义了两个函数 select_khard_emails
和 compose_with_khard
,它们协同工作,提供了一个非常强大的邮件撰写流程,包括选择收件人(To)、抄送人(CC),以及手动输入主题。
让我们先分解辅助函数 select_khard_emails
:
select_khard_emails () { ... }
: 定义了一个可重复使用的函数,其唯一目的是从khard
中选择并返回一个或多个邮箱地址。khard email --parsable
:khard email
命令用于提取联系人的邮箱地址。--parsable
参数使其输出格式变为机器友好的email@domain.com 姓名 UID
,非常适合后续的管道处理。
| grep -v "searching for 'ALL'..."
:khard
在执行时可能会输出一行状态信息,如searching for 'ALL'...
。grep -v
的作用是反向匹配,即过滤掉包含该文本的行,确保只有纯净的联系人数据进入下一步。| fzf --multi --preview '...' --header "..."
: 这是核心的交互界面。--multi
: 允许使用TAB
键选择多个联系人。--preview 'khard show {3}'
: 这是fzf
的一个高级功能。它会为当前高亮的行显示一个预览窗口。{3}
代表khard
输出的第三列,即联系人的 UID。因此,fzf
会实时执行khard show <UID>
,在预览窗口中显示该联系人的详细信息,非常方便。--header "..."
: 在fzf
窗口顶部显示帮助信息。
| awk '{print $1}'
:fzf
将选中的所有行(例如email@domain.com 姓名 UID
)输出给awk
。awk '{print $1}'
的作用是只打印每一行的第一个字段,也就是我们最终需要的邮箱地址。
接下来,我们分析主函数 compose_with_khard
:
compose_with_khard() { ... }
: 定义了主函数,也就是用户直接调用的函数。echo "Selecting 'To' recipients..."
: 向用户显示清晰的提示,告知当前正在选择“收件人”。local to_emails; to_emails=$(select_khard_emails)
: 调用我们上面定义的辅助函数来选择收件人,并将返回的、由换行符分隔的邮箱地址列表存入to_emails
变量。if [ -n "$to_emails" ]; then ... fi
: 检查用户是否至少选择了一个收件人。local to_list; to_list=$(echo "$to_emails" | paste -sd, -)
: 如果选择了,paste -sd, -
命令会将to_emails
中由换行符分隔的多行邮箱地址合并成一个由逗号,
分隔的单行字符串。to_headers=(--header "To:$to_list")
: 创建一个数组to_headers
,其中包含一个himalaya
能识别的参数,例如--header "To:a@x.com,b@y.com"
。
echo "Selecting 'CC' recipients (optional)..."
: 以完全相同的逻辑,提示并允许用户为“抄送”选择联系人,并将结果处理成cc_headers
数组。echo "Enter Subject: "
: 提示用户输入邮件主题,并通过read
命令将其存入SUBJECT
变量。himalaya message write ...
: 最后,调用himalaya
的撰写命令。"${to_headers[@]}"
和"${cc_headers[@]}"
: 这种${array[@]}
语法可以安全地将数组中的元素作为独立的参数传递给命令。如果用户没有选择收件人或抄送人,对应的数组为空,这里就不会传递任何参数,非常灵活。--header "Subject:$SUBJECT"
: 传递邮件主题。
执行此命令后,himalaya
会打开你的默认文本编辑器,邮件的 To, Cc, 和 Subject 头部字段都已经为你预先填好了。
总结与资源
通过将 himalaya
, khard
, fzf
, grep
, awk
, 和 paste
等多个强大的单一功能工具组合成 shell 函数,我们创造了一个功能完整、交互友好且极为高效的邮件撰写工作流。这完美地展示了 Unix 哲学的精髓所在:编写只做一件事并把它做好的程序,然后将它们组合起来以完成复杂的任务。
希望这篇教程能帮助你更好地在终端中管理你的数字生活。
待解问题
- 添加附件 一直报错...
- 回复邮件
- 转发邮件
- 本地保存邮件
- 多帐号支持