userapps:emacs:mu4e
no way to compare when less than two revisions
差分
このページの2つのバージョン間の差分を表示します。
| — | userapps:emacs:mu4e [2026/01/06 04:10] (現在) – 作成 - 外部編集 127.0.0.1 | ||
|---|---|---|---|
| 行 1: | 行 1: | ||
| + | ====== mu4e ====== | ||
| + | ===== まくら ===== | ||
| + | |||
| + | 元々は家でゲームがしたい(小学生のことTAITOのSpace Invaderが大ブームになった)という理由で始めたコンピューターとの付き合いが、いつの間にか人とのCommunicationの手段になったのは、明らかにパソコン通信のせいで、参加していたBBSのChat roomに入り浸るようになってからだったように思う。 | ||
| + | |||
| + | Unixを触るようになり、UUCPで自宅に居ながらにして電子メールが使えるようになって以来、数年前までは間違いなくE-Mailこそが他者とのCommunicationの中心にあった。 | ||
| + | したがって、筆者の場合、E-Mailの読み書きを簡単にできるようなApplicationが最も重要なツールであった時代が長い。 | ||
| + | |||
| + | そのため、メールクライアントは色々使ってきた。それなりの期間(最低でも半年以上)利用したツールは | ||
| + | * rmail | ||
| + | * Gnus (Emacs) | ||
| + | * mew | ||
| + | * Bekky | ||
| + | * WinBiff | ||
| + | * Apple Mail (macOS) | ||
| + | * Thunderbird (macOS/ | ||
| + | * Shylpheed (macOS) | ||
| + | と、幾つもあった。しかし、個人的な要件を満たすMail Readerはあまりなかった。動作するPlatformが限られていたり、表示が望み通りにならなかったり、EoLになったり... | ||
| + | |||
| + | というわけで、Sylpheedを卒業して次のMail Readerに移行することにした。 | ||
| + | |||
| + | ===== 準備 ===== | ||
| + | 今回の選択はmu4eである。 | ||
| + | mu4eはmuコマンドを利用したメールの検索機能を利用して、Emacs上でMailの読み書きを行うためのツールである。 | ||
| + | |||
| + | mu4eを利用してMailを処理するためにはいくつかの方法があるが、今回は以下の構成で行くことにした。 | ||
| + | |||
| + | * IMAPを利用して手元にメールを同期するsoftware → mbsync(isync) | ||
| + | * smtpを利用してメールを送信するsoftware | ||
| + | * Emacs → GNU Emacs 30 | ||
| + | * メール処理 | ||
| + | |||
| + | ==== mbsync ==== | ||
| + | mbsyncは、RemoteのMDA(IMAP Server)からメールを手元に持ってくるツールである。 | ||
| + | Mailboxの同期をEmacs上で行わないのでメールの取得とメールの処理を独立して行えるのがメリットである。 | ||
| + | なお、mu4eはメールボックスがありさえすれば良いので、mbsyncである必要はない。imapsyncなどいくつかのツールがあるので、好みのものを選べば良いだろう。 | ||
| + | |||
| + | 今回は、複数のアカウントをまとめて管理する前提で設定を行う。 | ||
| + | 設定の詳細は、man mbsyncなどしてman pageを見ること。 | ||
| + | ここでは、うちで動作した設定を改変して記述してある。 | ||
| + | 名前付け替えなどいくつかトリッキーなことをしているので、わからなければManualを読むべきである。 | ||
| + | |||
| + | なお、本記事においては、動作確認なども兼ねているためpasswordをrawで記載しているが、これはGPGなどを利用して暗号化するべきである。 | ||
| + | 暗号化の方法などはGoogleで検索すれば大量に出てくるので、そちらを参照のこと。 | ||
| + | |||
| + | < | ||
| + | # | ||
| + | # .mbsyncrc - configuration for mbsync. | ||
| + | # | ||
| + | |||
| + | ##### General Configuration | ||
| + | Create Both | ||
| + | Expunge Both | ||
| + | CopyArrivalDate yes | ||
| + | Sync All | ||
| + | SyncState * | ||
| + | |||
| + | ##### sample@example.com (Dovecot) | ||
| + | IMAPAccount sample_example | ||
| + | Host dovecot.example.com | ||
| + | Port 993 | ||
| + | User sample@example.com | ||
| + | Pass Ultra-Secret | ||
| + | SSLType IMAPS | ||
| + | |||
| + | ### IMAP Store configuration | ||
| + | IMAPStore mls_seirios-remote | ||
| + | Account mls_seirios | ||
| + | |||
| + | ### Maildir Store configuration | ||
| + | MaildirStore sample_example-local | ||
| + | SubFolders Verbatim | ||
| + | Path ~/ | ||
| + | Inbox ~/ | ||
| + | |||
| + | ### Channel Configuration | ||
| + | Channel sample_example-local | ||
| + | Far : | ||
| + | Near : | ||
| + | Patterns * | ||
| + | |||
| + | ##### sample@icloud.com (Apple Mail) | ||
| + | IMAPAccount sample_icloud | ||
| + | Host imap.mail.me.com | ||
| + | Port 993 | ||
| + | User sample@icloud.com | ||
| + | Pass Apple-Application-password-set-at-Apple | ||
| + | SSLType IMAPS | ||
| + | AuthMechs PLAIN | ||
| + | |||
| + | ### IMAP Store configuration | ||
| + | IMAPStore sample_icloud-remote | ||
| + | Account sample_icloud | ||
| + | |||
| + | ### Maildir Store configuration | ||
| + | MaildirStore sample_icloud-local | ||
| + | SubFolders Verbatim | ||
| + | Path ~/ | ||
| + | Inbox ~/ | ||
| + | |||
| + | ### Channel Configuration | ||
| + | Channel sample_icloud-base | ||
| + | Far : | ||
| + | Near : | ||
| + | Patterns * !Sent !"Sent Messages" | ||
| + | |||
| + | Channel sample_icloud-base-sent | ||
| + | Far : | ||
| + | Near : | ||
| + | |||
| + | Channel sample_icloud-base-spam | ||
| + | Far : | ||
| + | Near : | ||
| + | |||
| + | Channel sample_icloud-base-trash | ||
| + | Far : | ||
| + | Near : | ||
| + | |||
| + | Group sample_icloud | ||
| + | Channel sample_icloud-base | ||
| + | Channel sample_icloud-sent | ||
| + | Channel sample_icloud-spam | ||
| + | Channel sample_icloud-trash | ||
| + | |||
| + | ##### sample@gmail.com (Gmail) | ||
| + | ##### もし、GmailのIMAP Folderが日本語だった場合、Gmailから表示を英語モードにしておくこと。日本語だとうまくいかないことがある | ||
| + | IMAPAccount sample_gmail | ||
| + | Host imap.gmail.com | ||
| + | Port 993 | ||
| + | User sample@gmail.com | ||
| + | Pass Gmail-Application-password-set-at-Gmail | ||
| + | SSLType IMAPS | ||
| + | AuthMechs PLAIN | ||
| + | |||
| + | ### IMAP Store configuration | ||
| + | IMAPStore sample_gmail-remote | ||
| + | Account sample_gmail | ||
| + | |||
| + | ### Maildir Store configuration | ||
| + | MaildirStore sample_gmail-local | ||
| + | SubFolders Verbatim | ||
| + | Path ~/ | ||
| + | Inbox ~/ | ||
| + | |||
| + | ### Channel Configuration | ||
| + | Channel sample_gmail-base | ||
| + | Far : | ||
| + | Near : | ||
| + | Patterns * !" | ||
| + | |||
| + | Channel sample_gmail-sent | ||
| + | Far : | ||
| + | Near : | ||
| + | |||
| + | Channel sample_gmail-spam | ||
| + | Far : | ||
| + | Near : | ||
| + | |||
| + | Channel sample_gmail-trash | ||
| + | Far : | ||
| + | Near : | ||
| + | |||
| + | Group sample_gmail | ||
| + | Channel sample_gmail-base | ||
| + | Channel sample_gmail-sent | ||
| + | Channel sample_gmail-spam | ||
| + | Channel sample_gmail-trash | ||
| + | |||
| + | ##### sheo0147@yahoo.co.jp (Yahoo! Japan) | ||
| + | IMAPAccount sample_yahoo | ||
| + | Host imap.mail.yahoo.co.jp | ||
| + | Port 993 | ||
| + | User sample@yahoo.co.jp | ||
| + | Pass Ultra-Secret | ||
| + | SSLType IMAPS | ||
| + | |||
| + | ### IMAP Store configuration | ||
| + | IMAPStore sample_yahoo-remote | ||
| + | Account sample_yahoo | ||
| + | |||
| + | ### Maildir Store configuration | ||
| + | MaildirStore sample_yahoo-local | ||
| + | SubFolders Verbatim | ||
| + | Path ~/ | ||
| + | Inbox ~/ | ||
| + | |||
| + | ### Channel Configuration | ||
| + | Channel sample_yahoo-base | ||
| + | Far : | ||
| + | Near : | ||
| + | |||
| + | Channel sample_yahoo-spam | ||
| + | Far : | ||
| + | Near : | ||
| + | |||
| + | Group sheo0147_yahoo | ||
| + | Channel sample_yahoo-base | ||
| + | Channel sample_yahoo-spam | ||
| + | </ | ||
| + | |||
| + | ここまで設定したら、Directoryを作成し、mbsync -aを実行する | ||
| + | <code bash> | ||
| + | $ mkdir ~/Maildir | ||
| + | $ mkdir ~/ | ||
| + | $ mbsync -a | ||
| + | </ | ||
| + | |||
| + | これで、手元にMailが来たはず | ||
| + | |||
| + | <WRAP info round> | ||
| + | * yahooの設定の際にPatternsを削除しているのは意図的である。 | ||
| + | * 原因はよくわかっていないが、Yahooの場合だけ、Patternsを登録しているとInboxの同期に失敗する | ||
| + | * とりあえずPatternsを設定しなければうまく行くという不思議なことが起きているので、現時点では外す | ||
| + | </ | ||
| + | |||
| + | === muの初期化 === | ||
| + | |||
| + | Mailを取得したら、muでメールのIndexを作成する。 | ||
| + | muはXapianを利用している。Xapianは原則としてヨーロッパ系言語の検索が主眼なので、日本語検索は厳しいかと思っていたが、FLAG_NGRAMS=" | ||
| + | <code bash> | ||
| + | $ export XAPIAN_CJK_NGRAM=" | ||
| + | $ export FLAG_NGRAMS=" | ||
| + | $ mbsync -a | ||
| + | $ mu init --maildir=~/ | ||
| + | --my-address=sample@example.com \ | ||
| + | --my-address=sample@icloud.com \ | ||
| + | --my-address=sample@gmail.com \ | ||
| + | --my-address=sample@yahoo.co.jp | ||
| + | $ mu index | ||
| + | $ mu info store | ||
| + | .... | ||
| + | </ | ||
| + | |||
| + | ==== msmtp ==== | ||
| + | |||
| + | msmtpはSMTP Clientで、メールを送信する際に利用できる。 | ||
| + | |||
| + | 近年では、UCE/ | ||
| + | 電子メールの送信にあたっては、送信用のSMTPサーバー(MTA)がそのメールを送付する資格があるかどうかを確認(SPF, | ||
| + | 例えば sample@example.com がFromとなるメールを送信することができるMXを限定し、そこ以外から送られたものは迷惑メールもしくは攻撃メールの可能性が高いと判断する、などができるようになっている。 | ||
| + | |||
| + | したがって、自分のように「複数のメールアカウントを持って」おり、「それぞれを必要に応じて使い分ける」ような使い方をしている場合、メールを送付する際にどのMTAを利用すれば良いかいちいち判断し、適切なMTAからメールを送る必要がある。これを行うためのツールがmsmtpである。 | ||
| + | |||
| + | なお、mbsyncと同様、メール送信系をmsmtpにするべき強い理由はない。単にmsmtpの例が非常に多いから利用しているだけである。 | ||
| + | また、本記事の設定は動作確認なども兼ねているためpasswordをrawで記載している。しかし、生パスワードを設定ファイルに記載することはSecurity上の重大なリスクになる可能性が高い。したがって、これはGPGなどを利用して暗号化するべきである。 暗号化の方法などはman msmtpするなり、検索するなりすれば大量に出てくるので、そちらを参照のこと。 | ||
| + | |||
| + | 以下設定。上記mbsyncと合わせてある。 | ||
| + | |||
| + | < | ||
| + | # | ||
| + | # .msmtprc - configuration for msmtp. | ||
| + | # | ||
| + | |||
| + | defaults | ||
| + | logfile ~/ | ||
| + | |||
| + | ##### sample@example.com | ||
| + | account sample_example | ||
| + | auth on | ||
| + | host smtp.example.com | ||
| + | port 465 | ||
| + | protocol smtp | ||
| + | from sample@example.com | ||
| + | user sample@example.com | ||
| + | password Ultra_secret | ||
| + | tls on | ||
| + | tls_starttls off | ||
| + | |||
| + | ##### sample@icloud.com | ||
| + | # *** WARNING *** Must need STARTTLS. This site doesn' | ||
| + | account sample_icloud | ||
| + | auth on | ||
| + | host smtp.mail.me.com | ||
| + | port 587 | ||
| + | protocol smtp | ||
| + | from sample@icloud.com | ||
| + | user sample@icloud.com | ||
| + | password Apple-Application-password-set-at-Apple | ||
| + | tls on | ||
| + | tls_starttls on | ||
| + | |||
| + | ##### sample@gmail.com | ||
| + | account sample_gmail | ||
| + | auth on | ||
| + | host smtp.gmail.com | ||
| + | port 465 | ||
| + | protocol smtp | ||
| + | from sample@gmail.com | ||
| + | user sample@gmail.com | ||
| + | password Gmail-Application-password-set-at-Gmail | ||
| + | tls on | ||
| + | tls_starttls off | ||
| + | |||
| + | ##### sample@yahoo.co.jp | ||
| + | account sample_yahoo | ||
| + | auth on | ||
| + | host smtp.mail.yahoo.co.jp | ||
| + | port 465 | ||
| + | protocol smtp | ||
| + | from sample@yahoo.co.jp | ||
| + | user sample@yahoo.co.jp | ||
| + | password Ultra-Secret | ||
| + | tls on | ||
| + | tls_starttls off | ||
| + | |||
| + | account default : sample_example | ||
| + | </ | ||
| + | |||
| + | ==== mu4e ==== | ||
| + | mu4eの設定は、以下の理由で巨大になっています。こんなに難しいことしなくてもいい気はするんだけど... | ||
| + | |||
| + | * MultiAccount対応 | ||
| + | * Mailの取り扱いはAccountに関係なくシームレスに行える | ||
| + | * どこのINBOXに来たメールでも、別のサーバーにrefileできるようにしてある | ||
| + | * refile ruleを大きく書き換えて、正規表現も込みにしたruleをかけるようにした | ||
| + | * 送信サーバーは、メールのFromフィールドを見て自動で決定するようにした | ||
| + | |||
| + | まぁ、色々なところから色々設定持ってきたり、PerplexityやMS copilotのお世話になったりしてます。 | ||
| + | 難しいcodeは書いてないから、コメント見ながら読めばわかると思いたい。 | ||
| + | というかわかるということにします。 | ||
| + | |||
| + | <code - mu4e-init.el> | ||
| + | ;;; -*- lexical-binding: | ||
| + | ;;; ~/ | ||
| + | ;;; | ||
| + | ;;; last updated: 2026/01/02 | ||
| + | ;;; Author: HEO SeonMeyong < | ||
| + | ;;; | ||
| + | |||
| + | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| + | ;;; Tips | ||
| + | ;;; * Create new refile folder | ||
| + | ;;; $ mkdir -p ~/ | ||
| + | ;;; $ chmod -R 700 ~/ | ||
| + | ;;; $ mbsync -a | ||
| + | ;;; $ mu index | ||
| + | ;;; * 要するに、正しいpermissionで正しくFolder(Directory)を作成してmbsyncで同期してindexを張ればOK | ||
| + | ;;; * 逆に削除はDirectoryごと全部削除すればよさそう | ||
| + | |||
| + | ;;; Informations(Links) | ||
| + | ;;; * https:// | ||
| + | |||
| + | ;;; 定義・機能一覧: | ||
| + | ;;; - my/which: Homebrew と環境 PATH の両方で実行ファイルを探索するヘルパー | ||
| + | ;;; - my-mu4e-update-mail-and-index-async: | ||
| + | ;;; - my/ | ||
| + | ;;; - my/ | ||
| + | ;;; - キーバインド: | ||
| + | ;;; - ポリシー: | ||
| + | ;;; | ||
| + | ;;; よく調整するパラメータ (本ファイル内のコメントを検索してください): | ||
| + | ;;; * 定期更新間隔分: | ||
| + | ;;; * mbsync/ | ||
| + | ;;; * mu4e-context-policy / mu4e-compose-context-policy: | ||
| + | ;;; ' | ||
| + | ;;; * mu4e-headers-results-limit: | ||
| + | ;;; * display-buffer-alist: | ||
| + | ;;; ---------------------------------------------------------------------- | ||
| + | |||
| + | ;;; 小さなユーティリティ(実行ファイル探索と簡易コンテキスト生成) | ||
| + | (defun my/which (&rest candidates) | ||
| + | " | ||
| + | 候補は、絶対パス文字列とコマンド名の混在でよい。 | ||
| + | - 絶対パスが渡された場合: | ||
| + | - コマンド名が渡された場合: | ||
| + | |||
| + | 例: | ||
| + | | ||
| + | (seq-some (lambda (c) | ||
| + | (cond | ||
| + | | ||
| + | (t (executable-find c)))) | ||
| + | candidates)) | ||
| + | |||
| + | (defun my/ | ||
| + | "mu4e 用コンテキストを簡潔に生成する。 | ||
| + | NAME は識別名、MAILDIR-PREFIX は \"/ | ||
| + | SIGNATURE を与えると `message-signature` を設定する。 | ||
| + | |||
| + | 例: | ||
| + | | ||
| + | (make-mu4e-context | ||
| + | :name name | ||
| + | : | ||
| + | : | ||
| + | : | ||
| + | (when msg | ||
| + | | ||
| + | (mu4e-message-field msg : | ||
| + | :vars (append | ||
| + | `((user-mail-address . ,email) | ||
| + | (user-full-name | ||
| + | (mu4e-drafts-folder . ,(concat maildir-prefix "/ | ||
| + | (mu4e-sent-folder | ||
| + | (mu4e-trash-folder | ||
| + | (when signature | ||
| + | `((message-signature . , | ||
| + | |||
| + | |||
| + | ;;;; mu4e のロードパスを動的に追加(Intel / Apple Silicon 両対応) | ||
| + | (dolist (cand ' | ||
| + | "/ | ||
| + | (when (file-directory-p cand) | ||
| + | (add-to-list ' | ||
| + | |||
| + | ;;;; 起動時の自動更新を制御するトグル | ||
| + | ;; Toggle for legacy mu4e auto-update (built-in interval & startup hook) | ||
| + | ;; - When t: mu4e の定期更新 (`mu4e-update-interval`) を使う | ||
| + | ;; - When nil: 組み込みの auto update は無効にして、代わりに自作タイマーを使う | ||
| + | (defvar my/ | ||
| + | " | ||
| + | |||
| + | (leaf mu4e | ||
| + | :load-path "/ | ||
| + | :require t | ||
| + | :preface | ||
| + | ;; MIMEのHTML等を抑止(ロード前定義でOK) | ||
| + | ;; これにより本文表示は極力 text/plain を優先する。 | ||
| + | (with-eval-after-load " | ||
| + | (add-to-list ' | ||
| + | (add-to-list ' | ||
| + | |||
| + | :custom | ||
| + | ;; ---- 全体動作/ | ||
| + | ;; インデックス更新は常にバックグラウンドで(UIフリーズを避ける) | ||
| + | ((mu4e-index-update-in-background . t) ; Run mu index update asynchronously to avoid UI blocking | ||
| + | ;; Maildir と添付保存先 | ||
| + | | ||
| + | | ||
| + | ;; mbsync でメール移動時、ファイル名を変更(重複衝突などを回避) | ||
| + | | ||
| + | ;; 終了確認やモードライン表示 | ||
| + | | ||
| + | | ||
| + | | ||
| + | ;; 表示:本文ビューを右側へ固定(display-buffer-alist 併用) | ||
| + | | ||
| + | ;; ミニバッファに出る「Retrieving…」などの雑音を極力隠す | ||
| + | | ||
| + | ;; コンテキストの選択ポリシー(起動時は最初を採用) | ||
| + | | ||
| + | ;; ヘッダ表示系(関連メッセージ非表示、結果上限、スレッド表示等) | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | . ' | ||
| + | ;; 本文ビューのフィールド | ||
| + | | ||
| + | | ||
| + | . ' | ||
| + | :tags : | ||
| + | :path : | ||
| + | ;; Compose 時のコンテキスト選択ポリシー(マッチしなければ確認) | ||
| + | | ||
| + | ;; 署名の自動挿入は無効(コンテキストで signature を持つもののみ) | ||
| + | | ||
| + | ;; 送信系(mu4e を使い、sendmail 経由で送る) | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | ;; 既定ブックマーク(InboxやSPAMなどショートカット検索) | ||
| + | | ||
| + | . ' | ||
| + | (:name " | ||
| + | (:name " | ||
| + | (:name " | ||
| + | (:name " | ||
| + | (:name " | ||
| + | (:name " | ||
| + | (:name " | ||
| + | (:name " | ||
| + | (:name " | ||
| + | (:name " | ||
| + | (:name " | ||
| + | : | ||
| + | : | ||
| + | (:name " | ||
| + | : | ||
| + | : | ||
| + | ;; Maildir ショートカット(ジャンプキー) | ||
| + | | ||
| + | . '( | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | |||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | |||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | ;; 以下は「一覧に見せるため」の要素。: | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | (:maildir "/ | ||
| + | |||
| + | :config | ||
| + | ;; ---- 実行ファイルの場所を自動検出(Homebrew/ | ||
| + | ;; mu/msmtp の実行パスは GUI 起動時(PATHが引き継がれないケース)でも見つかるよう、 | ||
| + | ;; 絶対パス候補 → PATH の順に探索します。 | ||
| + | (setq mu4e-mu-binary | ||
| + | (setq sendmail-program (my/which "/ | ||
| + | |||
| + | ;; メールを取得するための設定 | ||
| + | (with-eval-after-load 'mu4e | ||
| + | ;; U(取得)で使うコマンドは常に設定しておく(スマートラッパーを使わない場面向け互換) | ||
| + | (let ((mbsync (my/which "/ | ||
| + | (setq mu4e-get-mail-command (and mbsync (concat mbsync " -a" | ||
| + | |||
| + | ;; 起動時/ | ||
| + | (if my/ | ||
| + | (progn | ||
| + | ;; 自動更新ON: | ||
| + | (setq mu4e-update-interval (* 10 60)) ; 10分(任意で変更) | ||
| + | ;; 既定の起動時更新フックは mu4e が勝手に登録するため、ここでは何もしない | ||
| + | ) | ||
| + | ;; 自動更新OFF: | ||
| + | (setq mu4e-update-interval nil) | ||
| + | (remove-hook ' | ||
| + | ;; U で取得したいので mu4e-get-mail-command は nil にしない(上で保持) | ||
| + | ) | ||
| + | |||
| + | ;; ビューの分割(本文は右側へ表示) | ||
| + | (add-to-list ' | ||
| + | | ||
| + | | ||
| + | (side . right) (window-width . 0.5))) | ||
| + | |||
| + | ;; モードライン名の微調整(ヘッダ検索中は短く) | ||
| + | (setq mode-name " | ||
| + | (add-hook ' | ||
| + | |||
| + | ;; ---- コンテキスト(簡潔化)---- | ||
| + | ;; 複数アカウント構成(各 :vars で Drafts/ | ||
| + | (setq mu4e-contexts | ||
| + | (list | ||
| + | | ||
| + | (concat " | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | |||
| + | ;; ---- Refile ルール(データ駆動)---- | ||
| + | ;; ルールは (FOLDER FIELD REGEX) のリスト。 | ||
| + | ;; FIELD は ' | ||
| + | ;; `my-mu4e-refile-message` は、MSG に適用して最初にマッチした folder を返す。 | ||
| + | (defvar my-mu4e-refile-rules | ||
| + | ' | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | ("/ | ||
| + | (defun my-mu4e-refile-message (msg) | ||
| + | " | ||
| + | - 'any は to/ | ||
| + | - 'rcpt は to/cc/bcc の受信側集合で判定" | ||
| + | (cl-loop for (folder field regex) in my-mu4e-refile-rules | ||
| + | for addresses = (pcase field | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | when (seq-some (lambda (addr) | ||
| + | (and addr (string-match-p regex | ||
| + | (downcase (if (listp addr) | ||
| + | (or (plist-get addr :email) "" | ||
| + | addr))))) | ||
| + | addresses) | ||
| + | | ||
| + | | ||
| + | |||
| + | ;; mu4e が参照するリファイル先決定関数。ルールマッチしなければ現在フォルダ。 | ||
| + | (setq mu4e-refile-folder | ||
| + | (lambda (msg) | ||
| + | (or (my-mu4e-refile-message msg) | ||
| + | (mu4e-message-field msg : | ||
| + | |||
| + | ;; ヘッダビュー内で「自動的にrefileマークを付ける」補助コマンド | ||
| + | (defun my-mu4e-auto-refile-process (msg) | ||
| + | (let ((target (funcall mu4e-refile-folder msg))) | ||
| + | (when (and target | ||
| + | (not (string= target (mu4e-message-field msg : | ||
| + | (mu4e-mark-set ' | ||
| + | (defun my-mu4e-auto-refile () | ||
| + | " | ||
| + | (interactive) | ||
| + | (let* ((current (mu4e-message-field (mu4e-message-at-point) :maildir)) | ||
| + | | ||
| + | (mu4e-headers-search query) | ||
| + | (add-hook ' | ||
| + | (defun my-mu4e-auto-refile-hook () | ||
| + | (remove-hook ' | ||
| + | (goto-char (point-min)) | ||
| + | (while (not (eobp)) | ||
| + | (let ((msg (mu4e-message-at-point))) | ||
| + | (my-mu4e-auto-refile-process msg)) | ||
| + | (forward-line)) | ||
| + | ;; マーク後、次の未読へ移動 | ||
| + | (mu4e-headers-next nil)) | ||
| + | (keymap-set mu4e-headers-mode-map " | ||
| + | |||
| + | ;; ---- 送信補助(msmtp選択/ | ||
| + | ;; Fromヘッダと msmtp アカウントの対応表(追加・変更はここへ) | ||
| + | (defvar my/ | ||
| + | ' | ||
| + | (" | ||
| + | (" | ||
| + | (" | ||
| + | (" | ||
| + | (" | ||
| + | (" | ||
| + | (" | ||
| + | (" | ||
| + | (" | ||
| + | (defun my-mu4e-set-msmtp-account () | ||
| + | "From ヘッダに基づき msmtp アカウントを自動選択する。 | ||
| + | - ヘッダから送信者アドレスを取り出し、`my/ | ||
| + | - 一致がない場合は何もしない(ユーザ手動選択に委ねる)" | ||
| + | (when (message-mail-p) | ||
| + | (save-excursion | ||
| + | (let* ((from (save-restriction | ||
| + | | ||
| + | (or (message-fetch-field " | ||
| + | (acct (seq-some (lambda (pair) | ||
| + | (and (string-match (regexp-quote (car pair)) from) | ||
| + | (cdr pair))) | ||
| + | | ||
| + | (when acct | ||
| + | (message "Using msmtp account: %s" acct) | ||
| + | (setq message-sendmail-extra-arguments (list " | ||
| + | (add-hook ' | ||
| + | |||
| + | (defun my-add-cc-and-bcc () | ||
| + | " | ||
| + | - Cc 行が存在しない場合は新規に付与 | ||
| + | - 既に自アドレスが含まれていれば何もしない" | ||
| + | (save-excursion | ||
| + | (goto-char (point-min)) | ||
| + | (if (re-search-forward " | ||
| + | (unless (re-search-forward (concat (regexp-quote user-mail-address)) | ||
| + | | ||
| + | (end-of-line) | ||
| + | (insert (if (looking-back "[, \t]" (max (point-min) (1- (point)))) | ||
| + | user-mail-address | ||
| + | (concat ", " user-mail-address)))) | ||
| + | (message-add-header (format "Cc: %s\n" user-mail-address)))) | ||
| + | (save-excursion (message-add-header "Bcc: \n"))) | ||
| + | (add-hook ' | ||
| + | |||
| + | (defun confirm-empty-subject () | ||
| + | " | ||
| + | 誤送信防止のための軽量ガード。" | ||
| + | (let ((sub (message-field-value " | ||
| + | (or (and sub (not (string-match "\\`[ \t]*\\'" | ||
| + | (yes-or-no-p " | ||
| + | (keyboard-quit)))) | ||
| + | (add-hook ' | ||
| + | |||
| + | ;; === ヘッダ表示のページング(N=残り全件を一気に追記) === | ||
| + | (defun my/ | ||
| + | " | ||
| + | (when (mu4e-current-buffer-type-p ' | ||
| + | (save-excursion | ||
| + | (goto-char (point-max)) | ||
| + | (forward-line -1) | ||
| + | (plist-get (mu4e-message-at-point) : | ||
| + | |||
| + | (defun my-mu4e-append-all-remaining () | ||
| + | " | ||
| + | この呼び出し中のみ `mu4e-search-full` を t にして上限を外す。" | ||
| + | (interactive) | ||
| + | (when (mu4e-current-buffer-type-p ' | ||
| + | (let* ((mu4e-search-full t) ;; ★ この関数の間だけ全件モード | ||
| + | | ||
| + | | ||
| + | ;; 念のため「ほぼ無限」上限もローカルに設定(古いmu4eへの互換) | ||
| + | | ||
| + | | ||
| + | (when-let ((query (mu4e-last-query))) | ||
| + | (message " | ||
| + | ;; append=t で結果を追記。last-msg をアンカーに、それより古い側を取得。 | ||
| + | (mu4e-search query nil nil t last-msg) | ||
| + | ;; 視認性のため末尾へ移動 | ||
| + | (goto-char (point-max)) | ||
| + | (forward-line -1) | ||
| + | ;; スレッド折りたたみを使っている場合は全畳みで見通しを確保 | ||
| + | (when (bound-and-true-p mu4e-thread-folding-mode) | ||
| + | (mu4e-headers-fold-all)) | ||
| + | (message " | ||
| + | |||
| + | ;; キーバインドの差し替え(N) | ||
| + | (keymap-set mu4e-headers-mode-map " | ||
| + | |||
| + | ;; === 非同期取得+インデックス更新(背景実行)と定期バックグラウンド更新 === | ||
| + | ;; Parameters: | ||
| + | ;; - mbsync path resolution: my/which tries / | ||
| + | ;; - Timer interval: call (my/ | ||
| + | ;; - Log buffer: " *mu4e-mbsync*" | ||
| + | ;; Behavior: | ||
| + | ;; - U: triggers async mbsync followed by mu4e-index-update when exit-code=0 | ||
| + | ;; - Startup: built-in mu4e auto update disabled; we rely on custom timer | ||
| + | ;; - Index updates run with mu4e-index-update-in-background=t to avoid blocking | ||
| + | (setq mu4e-index-update-in-background t) | ||
| + | |||
| + | (defun my-mu4e-update-mail-and-index-async () | ||
| + | "Run mbsync asynchronously and, upon success, trigger mu4e index update in background. | ||
| + | ENV/PATH NOTES: | ||
| + | - GUI起動のEmacsでは Homebrew の PATH が見えないことがある。必要なら exec-path-from-shell を併用。 | ||
| + | LOGGING: | ||
| + | - mbsync の標準出力/ | ||
| + | ERROR HANDLING: | ||
| + | - 非ゼロ終了コードの場合はバッファを表示して詳細を確認できる。" | ||
| + | (interactive) | ||
| + | (let* ((mbsync (my/which "/ | ||
| + | | ||
| + | (unless mbsync | ||
| + | (user-error " | ||
| + | (let ((buf (get-buffer-create " *mu4e-mbsync*" | ||
| + | (with-current-buffer buf (erase-buffer)) | ||
| + | (message " | ||
| + | (let ((proc (apply #' | ||
| + | (set-process-query-on-exit-flag proc nil) | ||
| + | (set-process-sentinel | ||
| + | proc | ||
| + | | ||
| + | (when (eq (process-status p) 'exit) | ||
| + | (let ((code (process-exit-status p))) | ||
| + | (if (= code 0) | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | code (buffer-name (process-buffer p))) | ||
| + | | ||
| + | |||
| + | ;; Uキーを非同期版に差し替え(メイン/ | ||
| + | (define-key mu4e-main-mode-map | ||
| + | #' | ||
| + | (define-key mu4e-headers-mode-map (kbd " | ||
| + | #' | ||
| + | |||
| + | ;; mu4e 自体の同期更新コマンドを使う場面へ互換のため文字列版も保持 | ||
| + | (let ((mbsync (my/which "/ | ||
| + | (setq mu4e-get-mail-command (and mbsync (concat mbsync " -a" | ||
| + | |||
| + | ;; --- 定期バックグラウンド更新(独自タイマー) --- | ||
| + | (defvar my/ | ||
| + | " | ||
| + | |||
| + | (defun my/ | ||
| + | " | ||
| + | |||
| + | Parameters: | ||
| + | MINUTES | ||
| + | Behavior: | ||
| + | - 既存タイマーがあればキャンセル。 | ||
| + | - 最初の実行は 10 秒後、その後 MINUTES ごとに繰り返し。 | ||
| + | - 非同期関数 my-mu4e-update-mail-and-index-async を使用。 | ||
| + | Tuning: | ||
| + | - 初回遅延 10 秒は必要に応じて変更可能(run-at-time の第一引数)。" | ||
| + | (when my/ | ||
| + | (cancel-timer my/ | ||
| + | (setq my/ | ||
| + | (run-at-time 30 (* minutes 60) #' | ||
| + | (message " | ||
| + | |||
| + | (defun my/ | ||
| + | " | ||
| + | 従量制ネットワークや一時的に負荷を避けたい場合に使用。" | ||
| + | (interactive) | ||
| + | (when my/ | ||
| + | (cancel-timer my/ | ||
| + | (setq my/ | ||
| + | (message " | ||
| + | |||
| + | ;; 既定では 10 分間隔で開始(好みに合わせて値を変更) | ||
| + | (my/ | ||
| + | |||
| + | ;;; 追加: スレッド折りたたみ(見通しを良くするUI拡張) | ||
| + | (leaf mu4e-thread-folding | ||
| + | :vc (:url " | ||
| + | :require t | ||
| + | :config | ||
| + | (define-key mu4e-headers-mode-map (kbd "< | ||
| + | (define-key mu4e-headers-mode-map (kbd "< | ||
| + | (define-key mu4e-headers-mode-map (kbd "< | ||
| + | (define-key mu4e-headers-mode-map (kbd "< | ||
| + | (define-key mu4e-headers-mode-map (kbd "< | ||
| + | (define-key mu4e-headers-mode-map (kbd "< | ||
| + | (add-hook ' | ||
| + | |||
| + | ;;; 必要なら明示ロード(smtpmail は組み込みだが、leaf で明示しておくと見通しが良い) | ||
| + | (leaf smtpmail :require t) | ||
| + | </ | ||
userapps/emacs/mu4e.txt · 最終更新: by 127.0.0.1
