タグ管理が徹底した爆速メールシステム!Emacs の notmuch で Gmail を読む

motmuch というメールシステムを導入したので、導入手順をまとめます。

notmuch とは

notmuch とは、タグベースの高速検索メールシステムだ。

タグベースというところが気にいって、今回試してみた。

日本語情報が皆無なので、先駆者になれるかと思って使ってみる。

前回、同じコンセプトのタグ管理メールシステム mu4e について調べた。

今回は、ライバルの notmuch ということだ。

環境

  • Ubuntu 16.04 LTS
  • notmuch 0.23.4… タグづけツール
  • Offlineimap 6.6.1 … ローカルディレクトリとリモートフォルダを同期するツール
  • msmtp 1.6.6… smtpmail を軽量化したメール送信用ツール

インストール方法

Ubuntu にインストールする。

[sourcecode language=”bash” title=””]
sudo apt-get install notmuch
[/sourcecode]

端末上で notmuch setup を入力すると、簡単なガイダンスが始まる。

質問に答えていく。mkdir ~/mail で notmuch 用のフォルダを作成。

そのあと、notmuch new と入力する。.~/mail/.notmuch という DB フォルダが作成される。

Emacs Frontend Interface の導入

notmuch は Emacs 専用ソフトではない。いろんなフロントエンド I/F が用意されている。 (cli, vim, emacs, mutt)

しかし、Emacs でメールを閲覧することが目的なので、Emacs I/F をインストールする。

git repository からインストールすることが推奨されている。

[sourcecode language=”bash” title=””]
sudo apt-get install libxapian-dev libgmime-2.6-dev libtalloc-dev zlib1g-dev python-sphinx
git clone git://notmuchmail.org/git/notmuch
./configure
make
make install
[/sourcecode]

notmuch の Emacs 設定

[sourcecode language=”emacs-lisp” title=””]
(require ‘notmuch)
[/sourcecode]

メールを受信する

Offlineimap

IMAP サーバーからメールを同期する Python ユーティリティ.

[sourcecode language=”bash” title=””]
sudo apt-get -y install offlineimap
[/sourcecode]

~/.offlineimaprc を作成する。ここでは、Inbox と Notes と Drafts を同期するように設定している。

[sourcecode language=”text” title=””]
[general]
accounts = main

[Account main]
localrepository = main-local
remoterepository = main-remote

[Repository main-local]
type = Maildir
localfolders = ~/mail/Gmail

[Repository main-remote]
type = Gmail
# maxconnections=1
remoteuser = fox10225fox@gmail.com
remotepass =
# realdelete=no
folderfilter = lambda foldername: foldername in ["INBOX", "Notes", "[Gmail]/Drafts"]
sslcacertfile = /etc/ssl/certs/ca-certificates.crt
[/sourcecode]

ターミナルより、offlineimap を入力することで、メールボックスを同期できる。

パスワードをかくす

設定ファイルは github で管理したいのだが、パスワードを晒すわけにはいかない。 netrc が使える。

[sourcecode language=”bash” title=””]
touch ~/.netrc
chmod 600 ~/.netrc
[/sourcecode]

.netrc の中身は次の通り。

[sourcecode language=”text” title=””]
machine imap.gmail.com
login fox10225fox@gmail.com
password
machine smtp.gmail.com
login fox10225fox@gmail.com
password
[/sourcecode]

デーモン化

offlineimap を定期的に動作させるためには、systemd サービスに登録する必要がある。 以下の wiki に手順が載っている。

または、.offlineimaprc の[Account]欄に以下を書く。

[sourcecode language=”bash” title=””]
autorefresh = 1
[/sourcecode]

cron に登録してもよい。

Post-sync hook

メールを受信したら、notmuch new を動作させて、インデックスを作成する。

.offlineimaprc の[Account]欄に以下を書く。

[sourcecode language=”bash” title=””]
postsynchook = /usr/bin/offlineimap-postsync
[/sourcecode]

offlineimap-postsync というスクリプトを作成する。そのなかに notmuch new と書く。

以下のファイルが参考になる。 この例では、notify-send で通知を表示したりログしたりしている。

メールを検索する

基本は、search 欄にキーワードを入れて検索する。

helm-i/f がある。

メールを送信する

msmtp を使う。

[sourcecode language=”emacs-lisp” title=””]
$ git clone git://git.code.sf.net/p/msmtp/code msmtp
$ cd msmtp
$ autoreconf -i
$ ./configure; make; make install
[/sourcecode]

.emacs の設定は以下の通り。

[sourcecode language=”emacs-lisp” title=””]
;; use msmtp
(setq message-send-mail-function ‘message-send-mail-with-sendmail)
(setq sendmail-program "msmtp")
;; tell msmtp to choose the SMTP server according to the from field in the outgoing email
(setq message-sendmail-extra-arguments ‘("–read-envelope-from"))
(setq message-sendmail-f-is-evil ‘t)

;; don’t keep message buffers around
(setq message-kill-buffer-on-exit t)
[/sourcecode]

Tips

ショートカット

[sourcecode language=”emacs-lisp” title=””]
(define-key notmuch-show-mode-map "\C-c\C-o" ‘browse-url-at-point)

(define-key notmuch-search-mode-map "g"
‘notmuch-poll-and-refresh-this-buffer)
(define-key notmuch-hello-mode-map "g"
‘notmuch-poll-and-refresh-this-buffer)

(define-key notmuch-search-mode-map "d"
(lambda ()
"toggle deleted tag for thread"
(interactive)
(if (member "deleted" (notmuch-search-get-tags))
(notmuch-search-tag ‘("-deleted"))
(notmuch-search-tag ‘("+deleted" "-inbox" "-unread")))))

(define-key notmuch-search-mode-map "!"
(lambda ()
"toggle unread tag for thread"
(interactive)
(if (member "unread" (notmuch-search-get-tags))
(notmuch-search-tag ‘("-unread"))
(notmuch-search-tag ‘("+unread")))))

(define-key notmuch-show-mode-map "d"
(lambda ()
"toggle deleted tag for message"
(interactive)
(if (member "deleted" (notmuch-show-get-tags))
(notmuch-show-tag ‘("-deleted"))
(notmuch-show-tag ‘("+deleted" "-inbox" "-unread")))))

(define-key notmuch-search-mode-map "a"
(lambda ()
"toggle archive"
(interactive)
(if (member "archive" (notmuch-search-get-tags))
(notmuch-search-tag ‘("-archive"))
(notmuch-search-tag ‘("+archive" "-inbox" "-unread")))))

(define-key notmuch-show-mode-map "a"
(lambda ()
"toggle archive"
(interactive)
(if (member "archive" (notmuch-show-get-tags))
(notmuch-show-tag ‘("-archive"))
(notmuch-show-tag ‘("+archive" "-inbox" "-unread")))))

(define-key notmuch-hello-mode-map "i"
(lambda ()
(interactive)
(notmuch-hello-search "tag:inbox")))

(define-key notmuch-hello-mode-map "u"
(lambda ()
(interactive)
(notmuch-hello-search "tag:unread")))

(define-key notmuch-hello-mode-map "a"
(lambda ()
(interactive)
(notmuch-hello-search "tag:archive")))
[/sourcecode]

org-mode 連携

org-store-link が使える。

[sourcecode language=”emacs-lisp” title=””]
(require ‘org-notmuch)
(define-key global-map "\C-cl" ‘org-store-link)
[/sourcecode]

日本語ワードが検索で引っかからないときの対応

日本語ワードが検索でうまく引っかかってない。 いろいろ調べた結果、以下の記事にたどり着いた。 この方法で検索がうまく動くようになった。

[sourcecode language=”bash” title=””]
$ export XAPIAN_CJK_NGRAM=1
$ notmuch dump > ~/Maildir/.notmuch/dump-$(date +%Y%m%d)
$ mv ~/Maildir/.notmuch/xapian{,.old}
$ notmuch new
$ notmuch restore –input~/Maildir/.notmuch/dump-$(date +%Y%m%d)
[/sourcecode]

mu4e と notmuch との比較

mu4e の方が使いやすい。なぜなら、

  • notmuch には、メールの削除の方法がない(わからない)
  • Gmail との同機の方法が面倒。

notmuch が mu4e より優れている点は、

  • タグ管理が より mu4e に比べて徹底している

削除の機能がないというところを考えると、 notmuch はそもそも膨大なデータを検索するためのソフトウェアで タグによる検索に徹底していて、 削除など必要ないという設計思想なのかもしれない。

この記事によると、mu4e よりも、notmuch のほうが圧倒的に高速のようだ。

purely tag and search based mail client

mu4e のほうが一見使いやすくみえるが、 上の記事を読むと最終的には notmuch に軍配が上がるのではないか?

よし、決めたぞ。notmuch を使うことにしよう。迷ったときは、マイナーな方を選ぶのだ!