1 Email 处理哲学

在使用 Emacs Mu/Mu4e 作为邮件客户端之前,我通过定义邮件规则将邮件进行分类并移动到相应的目录中。在每天检查 Email 列表的时候,对于不能立即处理的 Email,我会打上标记 (Flag) 以便于随后处理。也就是是说,我将带有标记的 Email 作为一个另外一个待办事项处理 (我使用 Emacs Org-mode 管理待办事项)。我希望能够把将待处理的 Email 整合进我的待办事项列表。很幸运的是,别人已经这样做了,我找到了 MASTER YOUR INBOX WITH MU4E AND ORG-MODE 这篇文章。这彻底改变了我处理 Email 的哲学。本文就是以该文章为基础,结合我日常处理 Email 的方法总结而成。

促使我改变的要点是:

邮箱不是待办事项列表 (your inbox is not a todo list)

我的邮件处理方式:

  • 使用 Mu/Mu4e 强大的邮件搜索能力,形成以邮件搜索(s + /) 为核心的模式。不用再费心的使用规则和不同的文件夹分类和管理邮件。
  • 通过组合 Mu4e 和 Org-mode,轻松的将待处理邮件创建为一个待办事项。

我的邮件处理工作流:

  • 检查邮件列表,Mu/Mu4e 提供强大的搜索能力,能够完全通过搜索处理邮件检查任务。
  • 如果当前的邮件是垃圾邮件,标记为垃圾邮件 (d|mu4e-headers-mark-for-trash)
  • 如果确定不会再访问该邮件,阅读并标记删除 (D|mu4e-headers-mark-for-delete)
  • 如果是可能还会查看的邮件,阅读并标记为归档 (r|mu4e-headers-mark-for-refile)
  • 有时间且能够在几分钟内快速处理的邮件,回复并标记为归档 (R|mu4e-compose-reply)
  • 如果需要时间处理和回复的邮件,添加到待办事项列表 (通过 C-c c t 命令)

2 安装 (for Mac)

  • 运行 brew install offlineimap 安装 offlineimap
  • 运行 brew install mu 安装 Mu/Mu4e

3 获取和索引 Maildir

Offlineimap 使用 .offlineimaprc 配置。offlineimap 支持在配置中使用 python 脚本,为了避免在配置文件中直接配置密码,我使用如下 python 脚本 (.offlineimap.py) 以从 macOS keychain 获取密码。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import json
import subprocess

def secure_string_for(account, service):
    # this relies on the macOS `security` tool
    return subprocess.check_output(["security",
                                    "find-internet-password",
                                    "-a", account,
                                    "-s", service,
                                    "-w"]).strip()

以下是我的 .offlineimaprc 配置:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
[general]
# 这里是我要配置的账户列表
accounts = yanghotmail,yangfoxmail

# python 脚本用于从 macOS keychain 获取密码
pythonfile = ~/.offlineimap.py

# 该配置防止由于网络导致 offlieimap 挂起
socktimeout = 60

[Account yanghotmail]
localrepository = Local
remoterepository = Remote
# 配置 utf8foldernames 选项为 True 以支持中文文件夹。
utf8foldernames = True

[Repository Local]
type = Maildir
localfolders = ~/Maildir/yanghotmail

[Repository Remote]
type = IMAP
remotehost = outlook.office365.com
remoteuser = tiedang.yang@hotmail.com
# 通过脚本从 macOS kechain 获取密码
remotepasseval = secure_string_for("tiedang.yang@hotmail.com","outlook.office365.com")
ssl = yes
maxconnections = 3
# 注意配置 sslcertfile (以 Mac 为例) 以避免报告 SSL error。
sslcacertfile = /usr/local/etc/openssl/cert.pem

[Account yangfoxmail]
localrepository = yangfoxmail-Local
remoterepository = yangfoxmail-Remote
utf8foldernames = True

[Repository yangfoxmail-Local]
type = Maildir
localfolders = ~/Maildir/yangfoxmail

[Repository yangfoxmail-Remote]
type = IMAP
remotehost = imap.qq.com
remoteuser = tiedang.yang@foxmail.com
remotepasseval = secure_string_for("tiedang.yang@foxmail.com", "imap.qq.com")
ssl = yes
maxconnections = 3
# 需要根据系统修改
sslcacertfile = /usr/local/etc/openssl/cert.pem

运行命令 offlineimap 以同步邮件:

1
2
3
4
5
6
7
8
$ offlineimap
OfflineIMAP 7.2.4
  Licensed under the GNU GPL v2 or any later version (with an OpenSSL exception)
imaplib2 v2.57 (bundled), Python v2.7.16, OpenSSL 1.1.1d  10 Sep 2019
Account sync {USERNAME}@hotmail.com:
 *** Processing account {USERNAME}@hotmail.com
Account sync {USERNAME}@hotmail.com:
 *** Finished account '{USERNAME}@hotmail.com' in 31:41

运行命令 mu 以检查系统是否能够正常工作:

1
2
3
4
5
6
7
8
$ mu index
indexing messages under /Users/junahan/Maildir [/Users/junahan/.mu/xapian]
/ processing mail; processed: 23550; updated/new: 23531, cleaned-up: 0
cleaning up messages [/Users/junahan/.mu/xapian]
- processing mail; processed: 47105; updated/new: 0, cleaned-up: 23543
elapsed: 53 second(s), ~ 888 msg/s
\ processing mail; processed: 47105; updated/new: 0, cleaned-up: 23543
elapsed: 204 second(s), ~ 230 msg/s

4 配置和运行 Mu4e

Mu4e 整合 offlineimap 和 mu,允许通过配置 mu4e-update-interval 以在后台定期检查和索引邮件。

4.1 简单 mu4e 配置

mu4e 不能通过 ELPA 安装,但在安装 mu 的过程中, mu4e 模块已经安装在系统中了,在我的系统中,安装位置是 /usr/local/share/emacs/site-lisp/mu/mu4e/

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
;; 根据您自己的 mu4e 安装路径替换 load-path
(add-to-list 'load-path "/usr/local/share/emacs/site-lisp/mu/mu4e")

(require 'mu4e)

;; 配置 mu4e 作为 MUA 以及基本的邮件信息配置
(setq mail-user-agent 'mu4e-user-agent)
(setq user-full-name "USER FULL NAME")
(setq user-mail-address "EMAIL ADDRESS")

;; 配置使用 offlieimap 收取邮件
(setq
  mu4e-get-mail-command "offlineimap"   ;; 使用 offlineimap 获取邮件
  mu4e-update-interval 300)             ;; 每五分钟检查邮件并更新索引 (配置单位:秒)

;; 配置默认 smtp 服务以使用 smtpmail mode 发送 Email
;; SMTP 服务需要认证,我采用 ~/.authinfo.gpg 的方式提供认证信息。
;; 有关 SMTP 认证, 参阅 https://www.emacswiki.org/emacs/SmtpAuth
(setq send-mail-function 'smtpmail-send-it
      message-send-mail-function 'smtpmail-send-it
      smtpmail-smtp-server  "smtp.office365.com"
      smtpmail-smtp-service 587
      ;; smtpmail-auth-credentials (())
      smtpmail-auth-credentials "~/.authinfo.gpg"
      smtpmail-stream-type  'starttls)

SMTP 服务需要认证,我采用 ~/.authinfo.gpg 的方式提供认证信息。有关 SMTP 认证的更多信息,请参阅 SmtpAuth

4.2 运行 mu4e

基于以上最简化配置,就可以在 Emacs 运行命令 M-x mu4e 启动并显示 mu4e-main-view

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
\* mu4e - mu for emacs version 1.2.0 C

  Basics

	* [j]ump to some maildir
	* enter a [s]earch query
	* [C]ompose a new message

  Bookmarks

	* [bu] Unread messages
	* [bt] Today's messages
	* [bw] Last 7 days
	* [bo] Last 1 days
	* [bm] Last 1 days (org mode)
	* [bs] sent
	* [bd] drafts
	* [bp] Messages with images

  Misc

	* [;]Switch context
	* [U]pdate email & database

	* [N]ews
	* [A]bout mu4e
	* [H]elp
	* [q]uit

5 View 间的基本关系和快捷键

对于日常使用,只要理解几个关键的 View 以及大约 10 个快捷键即可。几个关键的 View 之间的关系图如下:

有了以上的关系图,只需要记住几个基本的快捷键绑定即可:

快捷键 命令 说明
R 回复邮件 (Reply) 用于在 headers / message view 执行回复邮件动作
F 转发邮件 (Forward)
C 写邮件 (Compose)
E 编辑邮件 (Edit)
s 搜索邮件 (search) 执行 mu find 命令搜索邮件
j 跳转到 maildir (jump-to-maildir) maildir 之间跳转
b 书签搜索 (bookmark-search) 为经常使用的搜索配置书签,以快速执行邮件搜索动作
B 修改书签索引 (edit bookmark-search)
. 切换显示原始消息视图 (raw view (toggle))
q 退出 可作用于 main / headers / messages / raw 等视图用于退出当前视图

6 定制 mu4e-main-view

6.1 配置 bookmarks

Bookmarks 允许结合 b (先导快捷键) 自定义快捷键以快速搜索 Email。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
;; configure the bookmarks.
(setq mu4e-bookmarks
      '( ("flag:unread AND NOT flag:trashed"                    "Unread messages"                  ?u)
         ("date:today..now"                                     "Today's messages"                 ?t)
         ("date:7d..now"                                        "Last 7 days"                      ?w)
         ("date:1d..now AND NOT list:emacs-orgmode.gnu.org"     "Last 1 days"                      ?o)
         ("date:1d..now AND list:emacs-orgmode.gnu.org"         "Last 1 days (org mode)"           ?m)
         ("maildir:/sent"                                       "sent"                             ?s)
         ("maildir:/drafts"                                     "drafts"                           ?d)
         ("mime:image/*"                                        "Messages with images"             ?p)))

以上 Bookmarks 定义在 mu4e-main-view 显示如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Bookmarks

* [bu] Unread messages
* [bt] Today's messages
* [bw] Last 7 days
* [bo] Last 1 days
* [bm] Last 1 days (org mode)
* [bs] sent
* [bd] drafts
* [bp] Messages with images
  • 使用 bu 搜索未阅读消息
  • bt 搜索今天的消息
  • bw 搜索近一周的消息

6.2 显示 Maildirs 概览

使用 mu4e-maildirs-extensionmu4e-main-view 展示 Maildirs 概览。

1
2
3
;; Show mu4e maildirs summary in mu4e-main-view
(require 'mu4e-maildirs-extension)
(mu4e-maildirs-extension)

如下是以上配置在 mu4e-main-view 上显示的效果:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
Maildirs

* [u]pdate index & cache

- drafts (0/0)

- sent (0/0)

- Mail Account001 (161/8818)
	| Deleted (0/2)
	| Drafts (0/0)
	| Inbox (161/8715)
	| Junk (0/7)
	| Notes (0/0)
	| Outbox (0/0)
	| Sent (0/94)

| trash (0/0)

7 为邮件创建待办事项

org-mu4e 整合了 Mu4e 和 org-mode,轻松支持为邮件创建待办事项。可以通过添加如下配置来启用 org-mu4e。

1
2
3
4
;;store org-mode links to messages
(require 'org-mu4e)
;;store link to message if in header view, not to header query
(setq org-mu4e-link-query-in-headers-mode nil)

并更新您的 org-capture 配置如下

1
2
3
(setq org-capture-templates
      '(("t" "todo" entry (file+headline "~/todo.org" "Tasks")
         "* TODO [#A] %?\nSCHEDULED: %(org-insert-time-stamp (org-read-date nil t \"+0d\"))\n%a\n")))

注意这个配置中 %a 配置的用途是添加一个链接到创建 capture 的来源。

美妙的是,现在可以在浏览邮件的时候,随时通过 C-c c t 为当前正在浏览的邮件创建一个待办事项,现在,您可以放心的归档邮件,因为您知道可以随时通过代办事项列表的链接打开该邮件。

8 使用 mu4e context

使用 mu4e context 可以分别为不同的邮件账户配置不同的参数。我使用它来配置多个 SMTP 邮件服务以根据上下文来正确的切换发送邮件服务器。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
;; 配置默认 smtp 服务以使用 smtpmail mode 发送 Email
;; SMTP 服务需要认证,我们采用 ~/.authinfo.gpg 的方式提供认证信息。
;; 有关 SMTP 认证, 参阅 https://www.emacswiki.org/emacs/SmtpAuth
(setq send-mail-function 'smtpmail-send-it
      message-send-mail-function 'smtpmail-send-it
      smtpmail-smtp-server  "smtp.office365.com"
      smtpmail-smtp-service 587
      ;;smtpmail-starttls-credentials '(("smtp.office365.com" 587 nil nil))
      smtpmail-starttls-credentials "~/.authinfo.gpg"
      smtpmail-stream-type  'starttls)

;; 根据 from 邮件头使用正确的账户上下文发送 Email.
(setq message-sendmail-envelope-from 'header)

;; 该函数基于当前所在的 maildir 来判定所账户上下文。
(defun mu4e-message-maildir-matches (msg rx)
  (when rx
    (if (listp rx)
        ;; If rx is a list, try each one for a match
        (or (mu4e-message-maildir-matches msg (car rx))
            (mu4e-message-maildir-matches msg (cdr rx)))
      ;; Not a list, check rx
      (string-match rx (mu4e-message-field msg :maildir)))))

;;
(setq mu4e-contexts
      `( ,(make-mu4e-context
           :name "yanghotmail"
           :enter-func (lambda () (mu4e-message "Switch to the yanghotmail context"))
           :match-func (lambda (msg)
                         (when msg
                           (mu4e-message-maildir-matches msg "^/yanghotmail")))
           :leave-func (lambda () (mu4e-clear-caches))
           :vars '((user-mail-address            . "tiedang.yang@hotmail.com")
                   (user-full-name               . "Tiedang Yang")
                   (smtpmail-default-smtp-server . "smtp.office365.com")
                   (smtpmail-smtp-server         . "smtp.office365.com")
                   (smtpmail-smtp-service        . 587)
                   (smtpmail-stream-type         . starttls)
                   (mu4e-compose-signature       .
                                                 (concat
                                                  "Tiedang Yang\n"
                                                  "https://www.junahan.com\n"))))
         ,(make-mu4e-context
           :name "fyangfoxmail"
           :enter-func (lambda () (mu4e-message "Switch to the cesgroup context"))
           :match-func (lambda (msg)
                         (when msg
                           (mu4e-message-maildir-matches msg "^/yangfoxmail")))
           :leave-func (lambda () (mu4e-clear-caches))
           :vars '((user-mail-address            . "tiedang.yang@foxmail.com")
                   (user-full-name               . "Yang Tiedang")
                   (smtpmail-default-smtp-server . "smtp.qq.com")
                   (smtpmail-smtp-server         . "smtp.qq.com")
                   ;;(smtpmail-auth-credentials    . '(("smtp.qq.com" 587 "tiedang.yang@foxmail.com" nil)))
                   (smtpmail-smtp-service        . 587)
                   (smtpmail-stream-type         . ssl)
                   (mu4e-compose-signature       .
                                                 (concat
                                                  "Junahan Yang\n"
                                                  "https://www.junahan.com\n"))))))

以上配置允许通过 ;(mu4e-context-switch) 来切换上下文。能够在撰写 Email 或者回复 Email 的时候根据正确的根据上下文使用正确的 SMTP 服务器配置。

9 完整的配置

完整的配置,请参阅 我的 mu4e 配置

Figure 1: 我的 Mu4e

Figure 1: 我的 Mu4e

10 参考文献

  1. Category Mail, Emacs Wiki 有关 Mail 的方方面面。
  2. mu4e (mu-for-emacs) is an e-mail client for GNU Emacs.
  3. Mew is a mail reader for Emacs.
  4. Reading and writing email with emacs.
  5. offlineimap, software to dispose your mailbox(es) as a local Maildir(s).
  6. MASTER YOUR INBOX WITH MU4E AND ORG-MODE, your inbox is not a todo list.
  7. Better Email with mu4e, 2016.
  8. A COMPLETE GUIDE TO EMAIL IN EMACS USING MU AND MU4E, 2017.
  9. mu4e 0.9.18: E-Mailing with Emacs now even better, 2017.
  10. Sending queued mails in the background with mu4e, 2019.