Notmuch 是一个以标签 (tag) 为中心的邮件客户端,但其标签通常不会与 IMAP 文件夹同步。而且它本身无法在 maildir 文件夹(一个 folder 对应你邮件账户中的一个 mailbox)之间移动邮件。如果你只用 Notmuch 来读邮件,这种设置没什么问题。但是,如果你还在使用其他邮件客户端,比如在手机上,并且希望在所有设备上保持同步,情况就会变得比较复杂。
本节介绍一些 hack 的方案,以方便 maildir 文件夹之间移动邮件从而与 remote 邮箱同步更改,使得在不同设备上同时使用 Notmuch 和其他邮件客户端时不会出现不同步的问题。
在 Maildir 文件夹之间移动邮件的 shell 脚本
将以下文件放在你的 $PATH
下,并给它一个类似 movemail
的名字。
这个脚本改编自 Notmuch 邮件列表中的讨论。
这个脚本接受两个参数,第一个是邮件的文件路径,第二个是 Maildir 文件夹。通常第一个参数会在 notmuch hook 中通过 stdin 传入,第二个则是目标 maildir 位置。
#!/usr/bin/env bash
# move mails stored in maildir format between maildir folders. Mainly used as a
# pre-hook script executed at `notmuch new` command. This script also assumes
# the maildir synchronizer is mbsync/isync.
# `mbsync` requires an unique "UID" identifier for the filename of each mail.
# so the HEADER U=xxx should be removed before moving mails.
# remove the paths (leading characters), only containing the filename
only_last_file_name=${1##*/} # double #s indicates matching chars as many as possible.
# check if file if exists
if [ ! -f "$1" ];
then
echo "File $1 does not exist."
exit 0;
fi
# don't print the output of grep, just check the condition
if echo $1 | grep ':2,[PRSTDF]\{1,6\}' > /dev/null;
then
# print out messages of moving files
echo "Moving $1 to $2/cur/$(echo $only_last_file_name | sed 's/,U=[0-9]\{1,\}//')"
# move messages with flags to cur/ directory
mv -f "$1" "$2/cur/$(echo $only_last_file_name | sed 's/,U=[0-9]\{1,\}//')"
else
# print out messages of moving files
echo "Moving $1 to $2/new/$(echo $only_last_file_name | sed 's/,U=[0-9]\{1,\}//')"
# move messages with no flags to new/ directory
mv -f "$1" "$2/new/$(echo $only_last_file_name | sed 's/,U=[0-9]\{1,\}//')"
fi
整合上述 movemail 脚本的 Notmuch 配置
要整合 movemail 脚本,需要配置两个 Notmuch hooks:
- pre-new Hook
- 在
notmuch new
命令之前执行 - 管理 Maildir 文件夹之间的邮件迁移
- 在
- post-new Hook
- 在
notmuch new
命令之后执行 - 更新 Notmuch 标签以保证对应新的邮件位置
- 用对应的 Maildir 文件夹更新标签
- 在
Example pre-new script
#!/usr/bin/env bash
my_personal_gmail="$HOME/Maildir/my-personal-gmail"
my_personal_outlook="$HOME/Maildir/my-personal-outlook"
# action-delete
notmuch search --output=files --format=text0 "tag:action-delete and folder:/my-personal-gmail/" \
| xargs -r -0 -n1 -I{} movemail {} "$my_personal_gmail/[Gmail]/Trash"
notmuch search --output=files --format=text0 "tag:action-delete and folder:/my-personal-outlook/" \
| xargs -r -0 -n1 -I{} movemail {} "$my_personal_outlook/Deleted"
# action-archive
notmuch search --output=files --format=text0 "tag:action-archive and folder:/my-personal-gmail/" \
| xargs -r -0 -n1 -I{} movemail {} "$my_personal_gmail/Archive"
notmuch search --output=files --format=text0 "tag:action-archive and folder:/my-personal-outlook/" \
| xargs -r -0 -n1 -I{} movemail {} "$my_personal_outlook/Archive"
# action-spam
notmuch search --output=files --format=text0 "tag:action-spam and folder:/my-personal-gmail/" \
| xargs -r -0 -n1 -I{} movemail {} "$my_personal_gmail/[Gmail]/Spam"
notmuch search --output=files --format=text0 "tag:action-spam and folder:/my-personal-outlook/" \
| xargs -r -0 -n1 -I{} movemail {} "$my_personal_outlook/Junk"
# action-inbox
notmuch search --output=files --format=text0 "tag:action-inbox and folder:/my-personal-gmail/" \
| xargs -r -0 -n1 -I{} movemail {} "$my_personal_gmail/Inbox"
notmuch search --output=files --format=text0 "tag:action-inbox and folder:/my-personal-outlook/" \
| xargs -r -0 -n1 -I{} movemail {} "$my_personal_outlook/Inbox"
Example post-new script
#!/usr/bin/env bash
# Synchronization between maildir folders and tag
notmuch tag +sent -- folder:"/Sent/"
notmuch tag -sent -- not folder:"/Sent/"
notmuch tag +deleted -- folder:"/Trash/" or folder:"/Deleted/"
notmuch tag -deleted -- not folder:"/Trash/" and not folder:"/Deleted/"
notmuch tag +drafts -- folder:"/Drafts/" or folder:"/drafts/"
notmuch tag -drafts -- not folder:"/Drafts/" and not folder:"/drafts/"
notmuch tag +archive -- folder:"/Archive/"
notmuch tag -archive -- not folder:"/Archive/"
notmuch tag +spam -- folder:"/Spam/" or folder:"/Junk/"
notmuch tag -spam -- not folder:"/Spam/" and not folder:"/Junk/"
notmuch tag +inbox -- folder:"/Inbox/"
notmuch tag -inbox -- not folder:"/Inbox/"
notmuch tag -action-delete -- tag:deleted
notmuch tag -action-archive -- tag:archive
notmuch tag -action-spam -- tag:spam
notmuch tag -action-inbox -- tag:inbox
解释
pre-new hook 执行以下任务:
- 检查当前邮件的标签。如果邮件有
action-delete
标签,就将其移到相应邮件账户的垃圾箱文件夹。 - 对
action-archive
、action-spam
和action-inbox
应用相同的逻辑,将邮件移动到各自的文件夹。
post-new hook 执行两个主要的标签管理任务:
-
基于位置更新标签
- 为 sent folder 中的邮件分配
sent
标签 - 从不再 sent folder 中的邮件删除
sent
标签 - 对其他标签重复相同操作:archive、inbox 和 spam
- 为 sent folder 中的邮件分配
-
清理基于操作的标签
- 邮件移动后删除操作相关的标签(deleted、archive、spam、inbox)
- 文件夹转换成功后清理标签
- 防止对已处理的邮件重复操作
Emacs configuration
The following lines in my Emacs configuration reflect my tag setup:
(setq notmuch-tagging-keys '(("a" notmuch-archive-tags "Archive")
("u" notmuch-show-mark-read-tags "Mark read")
("f" ("+flagged") "Flag")
("s" ("+action-spam") "Mark as spam")
("d" ("+action-delete") "Delete"))
notmuch-archive-tags '("+action-archive")
notmuch-draft-tags '("+drafts")
mg-notmuch-deleted-tags "action-delete")
当我运行 notmuch-tag-jump
命令时,我可以给邮件标记特定的操作:
action-delete
用于删除邮件action-archive
用于归档邮件action-spam
用于将邮件标记为垃圾邮件
同步邮件的完整命令
notmuch new && mbsync -a && notmuch new
- 第一个
notmuch new
在 Maildir 文件夹之间移动邮件 - 第二个
notmuch new
索引新收到的邮件并更新本地的 notmuch database