mu4e(emacsのメールクライアント)

emacsでメールと言えば、wanderlust, mew等が有名だが、最近mu4e(mu4e: an e-mail client for emacs)ってのがあって割とよいらしい!
というのを、一ヶ月程以上前の@さん主催の関西emacs勉強会で聞いたので重い腰を上げて導入してみた。


仕組みざっくり言うと、offlineimap等でローカルにMaildir形式のメールディレクトリを作成し、muでそのデータベースを作成する。
そして、mu4eでmuをemacsから使ってメールを読んだり表示するようだ。

入れ方はマニュアルに書いてあるので、省略して...
普段メールアカウント(Gmail, work)を二つ使ってるのでその設定を記しておきます。


まず、offlineimapの設定として、以下の~/.offlineimaprcと~/.offlineimap.pyを準備する。
私用のメールサーバーは色々適当に設定してあるので、適宜読み変えてください!

[general]
accounts = Gmail, work
maxsyncaccounts = 4
socktimeout = 60
pythonfile = ~/.offlineimap.py

[Account Gmail]
localrepository = LocalGmail
remoterepository = RemoteGmail

[Account work]
localrepository = Localwork
remoterepository = Remotework

[Repository LocalGmail]
type = Maildir
localfolders = ~/Maildir/Gmail

[Repository Localwork]
type = Maildir
localfolders = ~/Maildir/work


[Repository RemoteGmail]
type = IMAP
remotehost = imap.gmail.com
remoteuser = mygmail-address
remotepasseval = get_password_emacs("imap.gmail.com", "993")
ssl = yes
maxconnections = 1
realdelete = no
#同期しないメールディレクトリの設定
folderfilter = lambda foldername: foldername not in ["[Gmail]/Spam", "[Gmail]/Important"]

[Repository Remotework]
type = IMAP
remotehost = mywork-imap-server
remoteuser = mywork-user
remotepasseval = get_password_emacs("mywork-imap-server", "secret")
ssl = yes
maxconnections = 1
realdelete = no
#!/usr/bin/python
#encoding:utf-8
import subprocess


def get_output(cmd):
    # Bunch of boilerplate to catch the output of a command:
    pipe = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    (output, errout) = pipe.communicate()
    assert pipe.returncode == 0 and not errout
    return output

def get_password_emacs(host, port):
    cmd = "emacsclient --eval '(offlineimap-get-password \"%s\" \"%s\")'" % (host,port)
    return get_output(cmd).strip().lstrip('"').rstrip('"')



そして以下を.emacsに追加。

(when (require 'mu4e nil t)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;                         For Switching setting                      ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  (setq mu4e-maildir "~/Maildir"
        mu4e-sent-folder "/work/INBOX.Sent"
        mu4e-drafts-folder "/work/INBOX.Drafts")

;; trashの自動選択
  (setq mu4e-trash-folder
        (lambda (msg)
          (cond
           ((string-match "/work/"
                          (or (mu4e-message-field msg :maildir) ""))
            "/work/INBOX.Trash")
           ((string-match "/Gmail/"
                          (or (mu4e-message-field msg :maildir) ""))
            "/Gmail/[Gmail].Trash")
           ))
        )

  (require 'smtpmail)

;; stmp serverの自動選択
  (setq my-mu4e-account-alist
        '(
          ("Gmail"
           (mu4e-sent-folder "/Gmail/[Gmail].Sent Mail")
           (mu4e-drafts-folder "/Gmail/[Gmail].Drafts")
           (user-mail-address "mygmail-address")
           (mu4e-sent-messages-behavior delete)
           (starttls-use-gnutls t)
           (smtpmail-starttls-credentials '(("smtp.gmail.com" 587 nil nil)))
           (smtpmail-auth-credentials '(("smtp.gmail.com" 587 "mygmail-address" nil)))
           (smtpmail-smtp-user "mygmail-address")
           (smtpmail-default-smtp-server "smtp.gmail.com")
           (smtpmail-smtp-server "smtp.gmail.com")
           (smtpmail-smtp-service 587)
           (message-signature nil)
           ;; add other variables here
           )
          ))
  (add-to-list 'jk-mu4e-account-alist
                 '("work"
                   (mu4e-sent-folder "/work/INBOX.Sent")
                   (mu4e-drafts-folder "/work/INBOX.Drafts")
                   (smtpmail-smtp-user "work-username")
                   (user-mail-address "work-address")
                   (mu4e-sent-messages-behavior sent)
                   (starttls-use-gnutls nil)
                   (smtpmail-default-smtp-server "work-smtpserver")
                   (smtpmail-smtp-server "worksmtpserver")
                   (smtpmail-smtp-service secret)
                   (message-signature (shell-command-to-string "cat ~/Mail/signature.txt"))
                   ;; add other variables here
                   ))

  (defun jk-mu4e-set-account ()
    "Set the account for composing a message."
    (let* ((account
            (if mu4e-compose-parent-message
                (let ((maildir (mu4e-msg-field mu4e-compose-parent-message :maildir)))
                  (string-match "/\\(.*?\\)/" maildir)
                  (match-string 1 maildir))
              (completing-read (format "Compose with account: (%s) "
                                       (mapconcat #'(lambda (var) (car var)) jk-mu4e-account-alist "/"))
                               (mapcar #'(lambda (var) (car var)) jk-mu4e-account-alist)
                               nil t nil nil (caar jk-mu4e-account-alist))))
           (account-vars (cdr (assoc account jk-mu4e-account-alist))))
      (if account-vars
          (mapc #'(lambda (var)
                    (set (car var) (cadr var)))
                account-vars))))
  (add-hook 'mu4e-compose-pre-hook 'jk-mu4e-set-account)

  (setq mu4e-maildir-shortcuts
        '(
          ("/work/INBOX"             . ?i)
          ("/work/INBOX.Sent" . ?s)
          ("/Gmail/Gmail" . ?g)
          ("/Gmail/INBOX" . ?n)
          ("/Gmail/[Gmail].Sent Mail" . ?e)
          ("/Gmail/[Gmail].All Mail" . ?a)
          ))





;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;                         For Default setting                        ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;




  (require 'org-mu4e)
  (setq mu4e-headers-fields
        '((:date .  25)
          (:flags . 6)
          (:from . 22)
          (:subject . nil)))
  (setq mu4e-user-mail-address-regexp "mywork-addres\\|mygmail-address")
  (setq message-kill-buffer-on-exit t)
  (setq mu4e-html2text-command "html2text -utf8 -width 72")
  ;; (setq mu4e-html2text-command nil)
  (setq mail-user-agent 'mu4e-user-agent)
  (setq message-send-mail-function 'smtpmail-send-it)
  (setq mu4e-get-mail-command "offlineimap"
        mu4e-update-interval 300)
  (setq mu4e-use-fancy-chars nil)
  (setq mu4e-attachment-dir "~/Downloads")
  (setq mu4e-view-show-images t
        mu4e-view-image-max-width 800)
  (set-language-environment "UTF-8")
  ;; For encrypting password
  (require 'epa-file)
  (epa-file-enable)
  (setq auth-sources '("~/.authinfo.gpg" "~/.authinfo" "~/.netrc"))

  (require 'netrc)
  (defun offlineimap-get-password (host port)
    (let* ((netrc (netrc-parse (expand-file-name "~/.authinfo.gpg")))
           (hostentry (netrc-machine netrc host port port)))
      (when hostentry (netrc-get hostentry "password"))))
  )

後は
~/.authinfo.gpgに以下のように、
メールサーバーのpasswardやらを書いてやればOK!

machine imap.gmail.com login gmail-address port 993 password secret
machine mywork-imap-server login mywork-address port secret password secret


これらの設定で使うと...
~/Maildir/workと~/Maildir/Gmailのディレクトリにそれぞれのアカウントのメールが同期されます。
まぁ細かいことが色々と抜けてる気がしますが、こんな感じで設定しました!
ほとんどは、マニュアルとmu-discuss(Google グループ)に書いてある設定です。

使ってみた感想は、悪くない!
ただ、wanderlustに比べると機能はまだまだ少ないって感じですね...
まぁmu-discussを見てるとそれなりに議論が行なわているようなのでまだまだ機能の追加は今後あると思います。