Spacemacsに乗り換えてみた（５）メーラ編

# はじめに

- ``Spacemacs``でメールを読み書きできるようにした
- ``mu4e``を使うことにした
- あとでいろいろ追記するつもりだけど、とりあえず送受信できるようになった


# 設定の方針

1. メール受信 : ``Gmail``からIMAPで受信する（``offlineimap``を使う）
2. メール送信 : ``Gmail``のSMTPを使って送信する（``msmtp``を使う）
3. メール検索 : ``mu``を使って受信したメールを検索できるようにする
4. メーラ : ``mu4e``を使って``Emacs``上でメールを受信・送信できるようにする

# インストールしたもの

```bash
$ brew install offlineimap
$ brew install msmtp
$ brew install mu --with-emacs
```
- ``offlineimap`` : ``IMAP``を使ってメールを受信するコマンド
- ``msmtp`` : メールを送信するコマンド
- ``mu`` : メールのインデックスを作成したり、検索するコマンド。``--with-emacs``オプションをつけてインストールする


# ``Gmail``のアプリパスワードの作成

- ``Gmail``の``IMAP``、``SMTP``を使うためにアプリパスワードを作る必要がある
- [Gmailヘルプ - アプリパスワードでログイン](https://support.google.com/mail/answer/185833?hl=ja)を参考に作成する
  - ``アプリを選択``：``その他（名前を入力）``（``EmacsMu4e``とかなんでもOK）
  - ``端末を選択``：入力不要（というか、できなくなる）
  - ``生成``
  - ``パスワード``：16桁の文字列（ターミナルで``$ pwgen -s 16 1``で自動生成した）


# メール受信：``OfflineIMAP``の設定

- ``Gmail``の``IMAP``サーバを使ってメールを受信できるようにした
- 設定ファイル ``~/.offlineimaprc`` を新規に作成した
- 設定内容は[GitLab snippet - offlineimap](https://gitlab.com/snippets/1682702)にまとめた

## ``.offlineimaprc``のサンプルの場所

```bash
$ locate offlineimap.conf
/usr/local/etc/offlineimap.conf
/usr/local/etc/offlineimap.conf.default
/usr/local/etc/offlineimap.conf.minimal
```

- ``OfflineIMAP``をインストールしたら、上記の設定サンプルもインストールされてた
- それぞれのファイルの使い方は、中に書いてあるのでよく読む


## ``.offlineimaprc``の作成

```bash
$ cp -n /usr/local/etc/offlineimap.conf.minimal ~/.offlineimaprc
$ chmod 600 ~/.offlineimaprc
```

- ``minimal``な設定ファイルをもとに、自分用に書き直すことにした
- ファイルのパーミッションは``600``にする


# メール送信：``MSMTP``の設定

- ``Gmail``の``SMTP``サーバを使ってメールを送信できるようにした
- 設定ファイル ``~/.msmtprc`` を新規に作成した
- 設定する内容は[GitLab snippet - msmtp](https://gitlab.com/snippets/1682728)にまとめた

## 送信テスト

設定ファイルが正しく動くのか、コマンドラインでテストした

```bash:送信テスト
$ msmtp -t ## 入力待ち状態になるので、下記の内容を入力する
To: 宛先を入力する（例：自分のGmailアドレス）
From: 送信元を入力する（例：自分のGmailアドレス）
Subject: 件名を入力する（例：MSMTPの送信テストだよ）
本文を入力する
（例：
　これはMSMTPの送信テストだよ。
　自分のGmail → 自分のGmailに送信）
# （C-dで終了すると送信される）
```

1. ``$ msmtp -t``で起動
2. 宛先を入力する：``To:``から自分で入力する
3. 送信元を入力する：``From:``から自分で入力する（省略した場合、設定ファイルの``account default``で指定したアドレスになる）
4. 件名を入力する：``Subject:``から入力する（例：``Subject: MSMTPの送信テストだよ``）
5. メールの送信：``C-d``で終了するとメールが送信される（送信のキャンセルは``C-c``）
6. 宛先に指定したメールボックスを確認する

# メール検索：``mu``の設定

- 特に設定することはない

# ``mu4e``レイヤーの読み込み

```emacs-lisp
(mu4e :variables
      mu4e-installation-path "/usr/local/Cellar/mu/1.0/share/emacs/site-lisp/mu/mu4e/")
```

- [spacemacs - mu4e](http://spacemacs.org/layers/+email/mu4e/README.html)に書いてあるとおりにする
- ``$ locate mu4e.el``などして``mu4e.el``があるディレクトリを探して設定する

# ``mu4e``のユーザ設定

```emacs-lisp
(defun dotspacemacs/user-config()
    ...
    ;; recentf
    (add-to-list 'recentf-exclude (expand-file-name "~/Maildir") )
    
    ;; mu4e
    (use-package mu4e
        :load-path "/usr/local/Cellar/mu/1.0/share/emacs/site-lisp/mu/mu4e/"
        :config
        (setq mu4e-drafts-folder "/Gmail/[Gmail].Drafts") ;; /drafts
        (setq mu4e-sent-folder "/Gmail/[Gmail].Sent Mail") ;; /sent
        (setq mu4e-trash-folder "/Gmail/[Gmail].Trash") ;; /trash
        (setq mu4e-attachment-dir "~/Downloads")
        (setq mu4e-update-interval (* 60 5)) ;; nil
        ;;(setq mu4e-use-fancy-chars t)
        (setq mu4e-headers-visible-lines 20) ;; 10
        (setq mu4e-headers-skip-duplicates t) ;; t
        (setq mu4e-sent-messages-behavior 'delete) ;; 'sent
        (setq mu4e-get-mail-command "offlineimap -o") ;; true
        (setq message-kill-buffer-on-exit t) ;; nil
        ;; mu4e - msmtp
        (setq message-send-mail-function 'message-send-mail-with-sendmail) ;; sendmail-query-once
        (setq sendmail-program "msmtp")  ;; /usr/sbin/sendmail
        ;;(setq message-sendmail-extra-arguments)
        ;;(setq message-sendmail-f-is-evil t) ;; nil

        ;; mu4e - multiple mail accounts
        (setq mu4e-contexts
              `( ,(make-mu4e-context
                   :name "work"
                   :enter-func (lambda () (mu4e-message "Entering WORK context"))
                   :leave-func (lambda () (mu4e-message "Leaving WORK context"))
                   :match-func (lambda (msg) (when msg (mu4e-message-contact-field-matches msg :to "YOUR_MAIL_ADDRESS@WORK")))
                   :vars '( (user-mail-address . "YOUR_MAIL_ADDRESS@WORK")
                            (user-full-name . "YOUR_NAME")
                            (mu4e-compose-signature . (concat "YOUR_SIGNATURE_LINE01\n"
                                                              "YOUR_SIGNATURE_LINE02\n"
                                                              "YOUR_SIGNATURE_LINE03"
                                                       )
                       ))
                   )
                 ,(make-mu4e-context
                   :name "home"
                   :enter-func (lambda () (mu4e-message "Switch to the Gmail context"))
                   :match-func (lambda (msg) (when msg (mu4e-message-contact-field-matches msg :to "YOUR_ADDRESS@GMAIL")))
                   :vars '( (user-mail-address . "YOUR_ADDRESS@GMAIL")
                            (user-full-name . "YOUR_NAME (Gmail)")
                            (mu4e-compose-signature . (concat "YOUR_SIGNATURE_LINE01\n"
                                                              "YOUR_SIGNATURE_LIEN02"
                                                      )
                           ))
                   )
                 )
              )
        )
    ...
)
```

- 基本的な設定内容は[GitLab snippet - emacs-mu4e](https://gitlab.com/snippets/1682724)にまとめた
- 以上は、``dotspacemacs/user-config`` に書いた設定から抜粋した
  - 設定に必要な箇所だけ抜き出してきたけれど、カッコの数があってるか心配・・・これを参考にする際は、うまいことやってください
  - ``smartparens``を有効にすれば、マッチしてるカッコを教えてくれる


## ``recentf-exclude``に``~/Maildir/``を追加した

```emacs-lisp
(add-to-list 'recentf-exclude (expand-file-name "~/Maildir/") )
```

- ``mu4e``をしばらく使ってみると分かるが、開いたメールも``recentf``に追加されてしまう
- メールのファイル本体を直接開くことはまずないため、除外リスト（``recentf-exclude``）に追加した


## ``use-package``で囲む理由

- 複数アカウントを設定する箇所（``mu4e-contexts``）で下記のエラーがでた
  - ``(Spacemacs) Error in dotspacemacs/user-config: Symbol’s function definition is void: make-mu4e-context``
- このエラーで検索したら[Issue #9176](https://github.com/syl20bnr/spacemacs/issues/9176)がヒット。``with-eval-after-load``しないといけないみたい。
- ``with-eval-after-load``の代わりに``use-pakcage``で囲むことにした
  - そのままだと``mu4e``の場所が分からないので、``:load-path``でディレクトリを指定する
  - ``mu4e``レイヤーの設定のときと重複するが、こうしておけば動くのだからよしとする

## 送信済みフォルダの設定

```emacs-lisp
(setq mu4e-drafts-folder "/Gmail/[Gmail].Drafts") ;; /drafts
(setq mu4e-sent-folder "/Gmail/[Gmail].Sent Mail") ;; /sent
(setq mu4e-trash-folder "/Gmail/[Gmail].Trash") ;; /trash
```

- ``mu4e-maildir``に対する相対パスで設定する
- ``OfflineIMAP``で設定した``localfolders = ~/Maildir/Gmail/``に合わせるようにする
  - GmailのSMTPを使わない場合は、デフォルトのまま使えばよい
  - ディレクトリが存在しない場合は、必要になったときに``Emacs``が聞いてくる

## 添付ファイルを保存するフォルダの設定

```emacs-lisp
(setq mu4e-attachment-dir "~/Downloads")
```

- 添付ファイルは``~/Downloads``に保存することにした

## 送信済みメールの保存方法
```emacs-lisp
(setq mu4e-sent-messages-behavior 'delete) ;; 'sent
```

- ``Gmail``がよきに取り計らってくれるそうなので、``'delete``もしくは``'trash``にしておけばよいらしい
- ``Gmail``のSMTPを使わない場合は、デフォルトの``'sent``にして、``mu4e-sent-folder``に保存する。``'delete``になっていると、送信したメッセージがどこかにいってしまう（というか、消えてしまう）ので、とても不便だった


## 自動更新のタイミングを設定

```
(setq mu4e-update-interval (* 60 5)) ;; nil
```

- デフォルトだと、インデックス（``mu index``）の自動更新はされない
- ``mu4e-update-interval``に秒数を指定する
- ``OfflineIMAP``の更新が３分間隔なので、こっちは５分間隔にした（適当）
  - あとで変更するときに分かりやすいように、``60 × 5``秒（=5分間隔）と書いた


## ``Headers view``の設定

```emacs-lisp
;;(setq mu4e-use-fancy-chars t)
(setq mu4e-headers-visible-lines 20) ;; 10
(setq mu4e-headers-skip-duplicates t) ;; t
(setq mu4e-headers-date-format "%F %T")
(setq mu4e-headers-fields '((:human-date . 20)
                            (:flags . 6)
                            (:mailing-list . 10)
                            (:from . 22)
                            (:subject)))
```

### ``mu4e-headers-visible-lines``

- ``Headers view``に表示させる行数を設定
- デフォルト（``10行``）だと少なく感じたので``20行``に変更した


### ``mu4e-headers-skip-duplicates``

- 重複したメッセージの表示方法
  - ``Gmail`` + ``OfflineIMAP``だと、ラベル管理の仕組みからメッセージが重複してしまうので、スキップさせることにした
- ``V``でトグルできる
- ``Message-ID``を見て、重複してるかどうかを判断している


### メール受信日時の表示方法の変更

- デフォルトでは``today``の場合は時刻、``older``の場合は日付を表示するようになっている
  - ``today``：``mu4e-headers-time-format``（時刻）
  - ``older``：``mu4e-headers-date-format``（日付）
- しばらく使っているうちに、``older``なメッセージにも受信時刻がほしいなと感じたのでで``mu4e-headers-date-format``を変更した
  - [mu4e-headers.el](https://github.com/djcb/mu/blob/master/mu4e/mu4e-headers.el)内の``mu4e-headers-date-format``を読むと、``format-time-string``関数で設定していることが分かった
  - [Time Parsing](https://www.gnu.org/software/emacs/manual/html_node/elisp/Time-Parsing.html)に記載されているフォーマットを使って設定する
  - ``%F``：``%Y-%m-%d``の省略形
  - ``%T``：``%H:%M:%S``の省略形
- ``日付``フィールドに表示する文字数を増やした
  - ``mu4e-headers-fields``の``:human-date``の文字数を``20``に変更した

## ``Message view``の設定

```emacs-lisp
(setq mu4e-view-date-format "%F %T") ;; %c
(setq mu4e-view-fields '(:from
                         :to
                         :cc
                         :subject
                         :flags
                         :date
                         :maildir
                         :mailing-list
                         :tags
                         :attachments
                         :signature
                         :decryption
                         :message-id
                         :path
                         :user-agent
                         )
      )
```

- メッセージ本文の頭に表示する情報を増やしてみた
- 日付の表示方法を``%c``から``%F %T``（``YYYY-mm-dd HH:MM:ss``）に変更した
  - ``:human-date``が使えなかったので、``mu4e-view-date-format``を修正した
- 重複したメッセージが本当に同じIDを持つのか知りたくて``:message-id``を表示するようにした
- メッセージの場所が分かるように``:path``を表示することにした
- 他の人のメーラ情報（``:user-agent``）も表示することにした

## オフラインで使う場合

```emacs-lisp
(setq smtpmail-queue-mail t)
(setq smtpmail-queue-dir "~/Maildir/queue/cur")
```

- 送信メールを``queue``に入れることができる
- ラップトップの場合、これを設定しておくといいかも


```bash
$ mu mkdir ~/Maildir/queue
$ touch ~/Maildir/queue/.noindex
```

- ``$ mu mkdir``を使って``~/Maildir/queue/``を作成する
- ``~/Maildir/queue/.noindex``を作成し、``mu index``の対象外にしておく


## アカウントの設定

```emacs-lisp
(setq mu4e-contexts
    `( ,(make-mu4e-context
         :name "work"
         :enter-func (lambda () (mu4e-message "Entering WORK context"))
         :leave-func (lambda () (mu4e-message "Leaving WORK context"))
         :match-func (lambda (msg) (when msg (mu4e-message-contact-field-matches msg :to "YOUR_MAIL_ADDRESS@WORK")))
         :vars '( (user-mail-address . "YOUR_MAIL_ADDRESS@WORK")
                   ...
                 )
         )
        ,(make-mu4e-context
          :name "home"
          ...
         )
    )
)
```

- すべてのアカウントは``mu4e-contexts``に追加する
- 個々のアカウントは``make-mu4e-context``で設定する
  - 設定できる項目は[mu4e-context.el](https://github.com/djcb/mu/blob/master/mu4e/mu4e-context.el)にある``defstruct mu4e-context``を読むのがよい
- ``:name``は``mu4e``上でアカウントを切り替えるのに使う名前。使いやすいのに設定すればよい（頭文字が同じにならないほうがよいと思う）

## その他の変数について

- あとで追記する予定

# 使い方

- いろいろ設定に関して書いていたら長くなってしまったが、使い方に関しても書いておく
- ``mu4e``には``Main View``、``Headers View``、``Message View``というモードがあるので、この3つのどれを使っているかを頭に入れておくと、操作が理解しやすくなると思う
  - ``Main View``：メールボックス（とかラベル）を選択するモード
  - ``Headers View``：件名表示、メールを選択するモード
  - ``Message View``：メールを読むモード

## キーバインド

| キー | 動作 |
|:-----:|-----|
| ``SPC a M`` | ``mu4e``を起動する |
| ``y`` | ``Message View``と``Headers View``を行き来する |
| ``C-j`` | 次のメールに移動 |
| ``C-k`` | 前のメールに移動 |
| ``C-S-u`` | アップデート（``offlineimap -o``を走らせる） |
| ``q`` | いろいろ``Quit``する |
| ``e`` | 添付ファイルをダウンロード（``Message View``） |


# 目次

1. [Spacemacsに乗り換えてみた（１）導入編](https://qiita.com/shotakaha/items/da1282327f0dbc1b6289)
2. [Spacemacsに乗り換えてみた（２）キーバインド編](https://qiita.com/shotakaha/items/bba69546c6cd43ed4927)
3. [Spacemacsに乗り換えてみた（３）レイヤー編](https://qiita.com/shotakaha/items/364fca7d09596d636a8b)
4. [Spacemacsに乗り換えてみた（４）ウェブ制作編](https://qiita.com/shotakaha/items/dcd11c3afade2f0efb49)
5. [Spacemacsに乗り換えてみた（５）メーラ編](https://qiita.com/shotakaha/items/e2ba10457fa9b8d6e895)
6. Spacemacsに乗り換えてみた（６）LaTeX編（予定）