himalaya:基于 Rust 的邮件客户端后端项目

CLI to manage emails

分支1Tags45
文件最后提交记录最后更新时间
1 个月前
1 年前
1 个月前
1 个月前
3 年前
1 个月前
1 个月前
1 个月前
1 个月前
1 个月前
3 个月前
3 个月前
1 个月前
1 个月前
4 个月前
1 个月前
1 个月前
1 个月前
2 个月前
1 个月前
2 个月前
1 年前
2 年前
2 年前
2 年前
1 个月前
Logo

📫 Himalaya

电子邮件管理命令行工具

Matrix Mastodon Sponsor

screenshot

目录

功能特性

  • 统一 API,涵盖邮箱、邮件头、标志、邮件正文和附件
  • 协议专属 API,完整暴露各后端全部功能
  • 支持 IMAP、SMTP、JMAP、Gmail(REST API)、Microsoft Graph(Outlook / Microsoft 365)
  • 支持 Maildir 规范、m2dir 规范
  • IMAP/SMTP 的简单认证支持:anonymous、login、plain、oauthbearer、xoauth2、scram-sha-256
  • JMAP 的 HTTP 认证支持:basic、bearer
  • TLS 支持:
    • Rustls + ring 加密
    • Rustls + aws 加密(需启用 rustls-aws 特性)
    • Native TLS(需启用 native-tls 特性)
  • 服务发现支持:
  • 通过 $ALL_PROXY 和 $HTTP_PROXY 支持 SOCKS5、HTTP 代理
  • TOML 配置,支持多账户
  • 通过 --json 输出 JSON 格式

Tip

Himalaya 使用 Rust 编写,并借助 cargo features 来启用后端支持。默认特性集在 Cargo.toml 中声明。

安装

预编译二进制

Himalaya 可以通过安装程序进行安装:

以 root 身份运行:

curl -sSL https://raw.githubusercontent.com/pimalaya/himalaya/master/install.sh | sudo sh

作为普通用户:

curl -sSL https://raw.githubusercontent.com/pimalaya/himalaya/master/install.sh | PREFIX=~/.local sh

以下命令将从 GitHub 的 releases 部分安装最新的二进制文件。

如需比最新版本更新的版本,请查看 releases GitHub 工作流,并查找 Artifacts 部分。这些预构建的二进制文件基于 master 分支构建。

Note

此类二进制文件使用默认的 cargo 功能构建。如果您需要特定功能,请使用其他安装方法。

Cargo

cargo install --locked --git https://github.com/pimalaya/himalaya.git

仅支持 IMAP+SMTP:

cargo install --locked --git https://github.com/pimalaya/himalaya.git \
  --no-default-features \
  --features imap,smtp,rustls-ring

Arch Linux

来自社区软件仓库:

pacman -S himalaya

或者从用户软件仓库安装:

git clone https://aur.archlinux.org/himalaya-git.git
cd himalaya-git
makepkg -isc

或者使用 yay:

yay -S himalaya-git

Homebrew

brew install himalaya

Note

Cargo 功能特性与 brew 不兼容。如需其他功能组合,请使用其他安装方式。

Scoop

scoop install himalaya

Fedora Linux/CentOS/RHEL

来自 COPR 仓库:

dnf copr enable atim/himalaya
dnf install himalaya

Nix

如果您已启用 Flakes 功能:

nix profile install github:pimalaya/himalaya

或者无需安装直接运行:

nix run github:pimalaya/himalaya

邮件源

git clone https://github.com/pimalaya/himalaya
cd himalaya
nix run

配置

运行 himalaya。当磁盘上不存在配置文件时,向导会提示输入账户名称和电子邮件地址,执行服务提供商自动发现(并行探测并合并 PACC、Thunderbird Autoconfiguration、RFC 6186 SRV 和 RFC 8620 JMAP 解析),使用发现的默认值填充 IMAP/SMTP(或 JMAP)提示,然后将结果写入磁盘。

持久化配置从以下路径中第一个有效的路径加载:

  • $XDG_CONFIG_HOME/himalaya/config.toml
  • $HOME/.config/himalaya/config.toml
  • $HOME/.himalayarc

这些与 himalaya-tui TUI 查找的路径相同:一份 TOML 文件同时支持两个二进制程序。仅 CLI 使用的字段和仅 TUI 使用的节可以共存而不产生错误。参见 config.sample.toml 获取带注释的模板。

使用 -c <PATH> 覆盖路径;可以一次传入多个路径,用 : 分隔。第一个路径作为基础配置,其余路径深度合并到其上。

要添加或重新配置账户,再次运行不带参数的 himalaya 向导,并将其输出的 TOML 重定向到(或合并到)你的配置文件中。没有就地编辑的子命令;himalaya account list 和 himalaya account check 用于检查和验证已声明的账户。

Proton Mail

Proton 不直接提供 IMAP/SMTP:请运行 Proton Bridge,它会在本地同步邮件,并在本地 IMAP/SMTP 端点上提供服务。密码使用 Bridge 生成的密码,而非你的 Proton 账户密码。

[accounts.proton]

imap.server = "imap://127.0.0.1:1143"
imap.sasl.plain.username = "example@proton.me"
imap.sasl.plain.password.command = "pass show proton-bridge"

smtp.server = "smtp://127.0.0.1:1025"
smtp.sasl.plain.username = "example@proton.me"
smtp.sasl.plain.password.command = "pass show proton-bridge"

为在本地链路上保持 TLS 加密,请导出由 Bridge 生成的证书并启用 STARTTLS:

imap.starttls = true
imap.tls.cert = "/path/to/exported/cert.pem"

smtp.starttls = true
smtp.tls.cert = "/path/to/exported/cert.pem"

Fastmail

Fastmail 需要为 IMAP/SMTP 提供应用专用密码,或为其原生 JMAP 端点提供 API 令牌。

[accounts.fastmail]

imap.server = "imaps://imap.fastmail.com"
imap.sasl.plain.username = "example@fastmail.com"
imap.sasl.plain.password.command = "pass show fastmail"

smtp.server = "smtps://smtp.fastmail.com"
smtp.sasl.plain.username = "example@fastmail.com"
smtp.sasl.plain.password.command = "pass show fastmail"

若要改用 JMAP,只需将 imap/smtp 配置块替换为单一的 jmap 块即可:

jmap.server = "https://api.fastmail.com/jmap/session"
jmap.auth.bearer.token.command = "pass show fastmail"

Gmail

Gmail 会拒绝通过 SASL PLAIN 方式使用账户密码:请生成一个应用专用密码(需开启两步验证),并通过 password.command 或 password.raw 将其传入。

[accounts.gmail]

imap.server = "imaps://imap.gmail.com:993"
imap.sasl.plain.username = "example@gmail.com"
imap.sasl.plain.password.command = "pass show gmail"

smtp.server = "smtps://smtp.gmail.com:465"
smtp.sasl.plain.username = "example@gmail.com"
smtp.sasl.plain.password.command = "pass show gmail"

mailbox.alias.inbox = "INBOX"
mailbox.alias.sent = "[Gmail]/Sent Mail"
mailbox.alias.drafts = "[Gmail]/Drafts"
mailbox.alias.trash = "[Gmail]/Trash"
mailbox.alias.archive = "[Gmail]/All Mail"

每个 Gmail 标签都会显示为顶层 IMAP 邮箱,特殊邮箱则位于 [Gmail]/ 前缀之下——在 shell 中请用引号包裹(-m "[Gmail]/Drafts"),或通过别名访问。[Gmail]/All Mail 是包含所有邮件的归档:为它设置别名后,“搜索全部”只需一个标记即可完成(himalaya envelope search -m archive ...)。

若要使用 Gmail 原生 REST API 而非 IMAP/SMTP,请将以上配置块替换为来自 ortie 等辅助工具的单个 OAuth 2.0 令牌:

gmail.auth.token.command = ["ortie", "token", "show", "-a", "gmail"]

标签在此处也会变为邮箱文件夹,但标签使用的是API的不透明标识符;按名称指定即可(-m Himalaya-Test),himalaya 会解析对应的ID。

Outlook

Microsoft 已停用基础身份验证:请通过 oauthbearer 或 xoauth2 使用 OAuth 2.0,访问令牌由外部辅助工具(如 ortie)提供。

[accounts.outlook]

imap.server = "imaps://outlook.office365.com:993"
imap.sasl.xoauth2.username = "example@outlook.com"
imap.sasl.xoauth2.token.command = ["ortie", "token", "show", "-a", "outlook"]

smtp.server = "smtp://smtp-mail.outlook.com:587"
smtp.starttls = true
smtp.sasl.xoauth2.username = "example@outlook.com"
smtp.sasl.xoauth2.token.command = ["ortie", "token", "show", "-a", "outlook"]

要使用原生的 Microsoft Graph API 替代 IMAP/SMTP,只需将上面的配置块替换为一个 OAuth 2.0 承载令牌即可(发送邮件同样通过 Graph 完成,因此无需 SMTP):

msgraph.auth.token.command = ["ortie", "token", "show", "-a", "msgraph"]

邮件文件夹携带Graph协议中的不透明文件夹ID;你可以通过名称(-m Archive)或通用名称(-m inbox)来指定它们,himalaya会解析对应的ID。

Posteo

使用常规账户密码的标准IMAP/SMTP——无需应用专用密码。

[accounts.posteo]

imap.server = "imaps://posteo.de"
imap.sasl.plain.username = "example@posteo.net"
imap.sasl.plain.password.command = "pass show posteo"

smtp.server = "smtps://posteo.de"
smtp.sasl.plain.username = "example@posteo.net"
smtp.sasl.plain.password.command = "pass show posteo"

iCloud Mail

根据 iCloud Mail 支持页面说明:IMAP 登录名为您的邮箱地址名称(如 johnappleseed,而非 johnappleseed@icloud.com),而 SMTP 登录名则为完整的邮箱地址,并且需要使用专用的应用专用密码。

[accounts.icloud]

imap.server = "imaps://imap.mail.me.com:993"
imap.sasl.plain.username = "johnappleseed"
imap.sasl.plain.password.command = "pass show icloud"

smtp.server = "smtp://smtp.mail.me.com:587"
smtp.starttls = true
smtp.sasl.plain.username = "johnappleseed@icloud.com"
smtp.sasl.plain.password.command = "pass show icloud"

mailbox.alias.sent = "Sent Messages"

使用方法

每条命令都自带 --help 选项,这是其标志和语法的最权威参考。以下片段仅展示部分功能。

通用 API

与后端无关的命令默认在账户首个配置的后端上运行,或通过 -b/--backend 选项指定后端。当在 [mailbox.alias] 下设置了 inbox 别名时,-m/--mailbox 将默认使用该别名。

himalaya mailbox list
himalaya envelope list --page 2
himalaya envelope search from alice and after 2026-01-01 order by date desc
himalaya flag add --flag seen 1:3,5
himalaya message read 42
himalaya message copy --from INBOX --to Archives 42
himalaya attachment download 42

envelope search 使用 himalaya 自有的跨后端查询 DSL;其语法详见 himalaya envelope search --help。

协议特定 API

每个后端还会在其专属子组下公开完整的原生 API,始终针对该后端运行(此处忽略 -b/--backend 选项):

himalaya imap raw 'a1 SEARCH FROM "alice@example.com"\r\n'
himalaya jmap mailbox query --role drafts
himalaya gmail messages list -q "from:alice is:unread"
himalaya msgraph mail-folder list
himalaya smtp send -f me@example.com -t you@example.com < message.eml

编写邮件

通过命令行选项,message compose、reply 和 forward 可应对简单场景。若需处理丰富的 MIME 内容(如 MML 指令、签名、加密及编辑器驱动的流程),可将 mml 等编辑器接入 message send 或 message add 命令,或将准备好的文件暂存为草稿:

himalaya message compose --to you@example.org --subject Hello --body Hi --send
mml compose >(himalaya message send)
himalaya message add -m drafts --flag draft < message.eml

请参阅 himalaya message send --help 和 mml 文档,了解如何串联使用邮件撰写器。

复用会话

每次调用都会新建一个 TCP+TLS+SASL 会话。为了分摊握手开销,可将 himalaya 与 sirup 配合使用:它通过 Unix 套接字提供预先认证的 IMAP/SMTP 会话,imap.server / smtp.server 可指向该套接字。

接口

Himalaya CLI 是 Pimalaya 库的多个前端之一:

常见问题

它与 aerc、mutt 或 alpine 有何不同?

Aerc、mutt 和 alpine 可归类为终端用户界面(TUI)。程序运行时,你的终端会进入事件循环,通过按键与邮件交互。

Himalaya 是一个命令行界面(CLI)。它没有事件循环:你通过 shell 命令以无状态方式与邮件交互。

专门构建的 TUI(himalaya-tui)正在基于相同的 Pimalaya 库积极开发中,它更接近 aerc、mutt 和 alpine。

密钥是如何解析的?

每个 *.passwd / *.password / *.token 字段都可以填写原始字面量,或者一个在 stdout 上输出密钥的 shell 命令。原始形式便于测试,但不应在生产环境中使用:

</需要翻译的内容>

  imap.sasl.plain.passwd.raw = "***"
  imap.sasl.plain.passwd.command = "pass show example"
  imap.sasl.plain.passwd.command = ["pass", "show", "example"]
v2 版本移除了原生密钥环支持,请使用第三方密钥环 CLI(如 `pass`、`secret-tool`、`gopass` 等)作为 `command`。
OAuth 2.0 是如何处理的?

v2 版本不内置 OAuth 流程。请使用 pimalaya/ortie(或其他任何令牌代理)获取访问令牌,然后将其作为 command 接入,在标准输出中返回令牌。对于 JMAP,将 jmap.auth.bearer.token.command 指向该代理;对于 IMAP/SMTP,通过使用命令来源密码的 SASL 机制路由 bearer 令牌。

向导是如何发现 IMAP/SMTP/JMAP 配置的?

向导会在电子邮件地址域名上并行探测多种发现机制,合并结果后为每个服务保留最安全的端点:

  • PACC draft-ietf-mailmaint-pacc-02:well-known JSON,通过 _ua-auto-config TXT 记录进行摘要验证。
    • Thunderbird 自动配置:ISP 主配置 / well-known / ISPDB 查找,然后基于 MX 重试,最后尝试 mailconf=<URL> TXT 重定向。
    • RFC 6186 SRV:_imap._tcp、_imaps._tcp、_submission._tcp 查找汇总为单一报告。
    • RFC 8620 JMAP:SRV 记录和 /.well-known/jmap 会话资源。

最终的 WWW-Authenticate 探测用于细化通告的认证方案,检测到 Google 或 Microsoft 账户时会直接跳转到其专属配置。完整的链路请参阅 io-pim-discovery。

如何调试 Himalaya?

使用 --log-level <level>(别名 --log),其中 <level> 为 off、error、warn、info、debug、trace 之一:

  himalaya --log trace mailbox list

当未使用 --log 参数时,系统会读取 RUST_LOG 环境变量,该变量支持按目标进行过滤(参见 env_logger 文档)。设置 RUST_BACKTRACE=1 可启用完整的错误回溯信息。

日志输出至 stderr,因此可轻松重定向到文件:

  himalaya --log trace mailbox list 2>/tmp/himalaya.log

您也可以通过 --log-file <path> 参数将日志直接输出到文件中:

  himalaya --log trace --log-file /tmp/himalaya.log mailbox list
如何禁用彩色输出?

在环境中设置 NO_COLOR=1 即可。

许可证

本项目采用以下任一许可证授权:

社区

赞助

nlnet

特别感谢 NLnet 基金会 和 欧盟委员会 多年来对该项目的资金支持:

本程序是 Pimalaya 的一部分,完全由资助和捐赠支持的自由软件。如果您觉得它有用,请考虑赞助其开发:

GitHub Ko-fi Buy Me a Coffee Liberapay thanks.dev PayPal

项目介绍

命令行界面管理电子邮件【此简介由AI生成】

定制我的领域
437.32 K241访问 GitHub