Mutt-wizardでGmailをOAuth 2.0で使う完全ガイド(Mac編)
ターミナルでEmail操作を求めて
このブログのソースコードをGitHubのRepositoryに追加し、coreの部分をnpmのライブラリへと初めてアップロードしました。
- GitHub Repository: a-lost-social-misfit/terminal-blog
- npm: md-blog-core
次は何しようかなと考え、WezTermとprojectディレクトリをnvimで行ったり来たりしていると…
mail確認、操作もcliでできないかな?
完全に思いつきです。昔ならGoogle検索をしても、求めるような記事・情報は出て来なかったでしょう。更に言うと英語も理解できないために、パソコンを壊してしまうのではないかと諦めていた事でしょう。
⚠️ この記事の構成について
この記事は私の実際の試行錯誤を時系列で記録したものです。
最初は失敗しました。 トークンファイルが頻繁にGPG暗号化される問題に何度も直面し、--encryption-pipe catで暗号化を回避しようとしましたが、結局うまくいきませんでした。
最終的に成功した方法は、GPG暗号化と戦わず、mutt-wizardの設計思想に従うことでした。
- 失敗した試み(第一部) - 最初のセットアップと遭遇した問題
- 成功した最終手順(第二部) - GPGを受け入れた安定した設定
はじめに
Mutt-wizardを昨日発見し、Xserverの独自ドメインメールアドレスをやっとの思いで登録することができました。しかし、欲深な僕はどうしても、Gmailも統合したくなりました。
Gmailは通常のパスワード認証では使えず、OAuth 2.0認証が必要です。日本語の記事があまり落ちていなく最新情報でもありませんでしたので、今回ここに人柱の不適合者が書き記そうと思います。
参考にした情報:
環境:
- macOS(M2 MacBookAir 8GB 256GB ※俗にいう貧困Mac)
- WezTerm
- Neomutt
- Mutt-wizard
- nvim(メール作成用エディタ)
第一部:最初の試み(失敗編)
前提条件
以下がインストール済みであること:
brew install neomutt isync msmtp gnupg python3
Mutt-wizardは私の環境では~/.local/src/へとクローンさせて頂きました。
手順1: 必要なパッケージのインストール
# Homebrewでインストール
brew install gnupg python3
# mutt_oauth2.pyスクリプトの取得
mkdir -p ~/.config/mutt
cd ~/.config/mutt/
curl -O https://raw.githubusercontent.com/neomutt/neomutt/main/contrib/oauth2/mutt_oauth2.py
chmod +x mutt_oauth2.py
手順2: Google Cloud Consoleでの設定
2-1. プロジェクトの作成
- Google Cloud Consoleにアクセス
- 新しいプロジェクトを作成(例: "mutt-gmail")
2-2. Gmail APIの有効化
- 「APIとサービス」→「有効なAPIとサービス」
- 「+ APIとサービスの有効化」をクリック
- "Gmail API"を検索して有効化
2-3. OAuth同意画面の設定
- 「OAuth同意画面」をクリック
- User Type: Externalを選択(個人Gmailアカウントの場合)
- アプリ情報を入力:
- アプリ名: 任意(例: "Mutt Email Client")
- ユーザーサポートメール: あなたのGmailアドレス
- デベロッパーの連絡先: あなたのGmailアドレス
苦戦したポイント:
- User Typeで「内部」を選択しようとしたが、個人Gmailでは「External」が必須
2-4. スコープの追加
- 左の欄にある「データアクセス」からスコープの追加に進む
- 「スコープの手動追加」で以下を入力:
https://mail.google.com/ - 「テーブルに追加」をクリック
苦戦したポイント:
- スコープ追加時に検索では見つからず、手動追加が必要だった
2-5. テストユーザーの追加
- 「対象」から「ADD USERS」をクリック
- あなたのGmailアドレスを追加
2-6. OAuthクライアントIDの作成
- 「クライアント」→「+ クライアントを作成」
- アプリケーションの種類: デスクトップ アプリ
- 名前: 任意(例: "Mutt")
- 「作成」をクリック
- Client IDとClient Secretをメモ(後で使用)
手順3: OAuth 2.0トークンの取得(失敗版)
⚠️ 注意:この方法は最終的にうまくいきませんでした
以下のコマンドを実行(YOUR_CLIENT_IDとYOUR_CLIENT_SECRETを実際の値に置き換える):
python3 ~/.config/mutt/mutt_oauth2.py \
--authorize \
--authflow localhostauthcode \
--encryption-pipe cat \
--client-id YOUR_CLIENT_ID.apps.googleusercontent.com \
--client-secret YOUR_CLIENT_SECRET \
--provider google \
--email your-email@gmail.com \
~/.config/mutt/gmail.tokens
実行すると:
- ブラウザが開く(またはURLが表示される)
- Googleアカウントでログイン
- 「このアプリは確認されていません」という警告が出る
- 「続行」をクリック
- アクセス権限を許可
苦戦したポイント:
- 最初
--authflowを指定せず、対話式で訳も分からずMacのパスキーを誤入力してしまった --encryption-pipe catを使ってGPG暗号化を回避しようとしたが、後で問題が発生
遭遇した問題1: トークンファイルが勝手にGPG暗号化される
症状
Neomuttでメール送受信を試みると、以下のエラーが頻繁に発生:
No authenticators available or wrong credentials
トークン確認コマンドを実行すると:
python3 ~/.config/mutt/mutt_oauth2.py --decryption-pipe cat ~/.config/mutt/gmail.tokens
エラー:
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x85 in position 0: invalid start byte
原因の特定
トークンファイルの状態を確認:
file ~/.config/mutt/gmail.tokens
結果:
PGP RSA encrypted session key - keyid: F9C887DF A191174D RSA (Encrypt or Sign) 4096b
原因判明:トークンファイルが勝手にGPG暗号化されていた
--encryption-pipe catを指定しているにも関わらず、何らかのプロセスがトークンファイルをGPG暗号化していました。
失敗した対策:トークンファイルを移動
最初は~/.config/mutt/の外に移動することで解決しようとしました:
# 新しいディレクトリを作成
mkdir -p ~/.local/etc/oauth-tokens
# 古いトークンファイルを削除
rm ~/.config/mutt/gmail.tokens
# 新しい場所にトークンを作成
python3 ~/.config/mutt/mutt_oauth2.py \
--authorize \
--authflow localhostauthcode \
--encryption-pipe cat \
--client-id YOUR_CLIENT_ID \
--client-secret YOUR_CLIENT_SECRET \
--provider google \
--email your-email@gmail.com \
~/.local/etc/oauth-tokens/gmail.tokens
設定ファイルも更新:
# OAuth 2.0 authentication
set imap_oauth_refresh_command = "python3 ~/.config/mutt/mutt_oauth2.py --decryption-pipe cat ~/.local/etc/oauth-tokens/gmail.tokens"
set smtp_oauth_refresh_command = "python3 ~/.config/mutt/mutt_oauth2.py --decryption-pipe cat ~/.local/etc/oauth-tokens/gmail.tokens"
結果:これでも数時間後にトークンファイルが再び暗号化されてしまった
遭遇した問題2: サイドバーが機能しない
症状
- サイドバーにフォルダリストは表示される
Ctrl + j/Ctrl + kで上下移動はできるCtrl + oで開こうとしても機能しない- フォルダのメール数が常に0のまま
原因
- mbsyncの設定がない(IMAP直接接続モード)
mail_check_statsがIMAPダイレクト接続では機能しない
対策:サイドバーを無効化してマクロで切り替え
# Sidebar settings
set sidebar_visible = no
# フォルダ切り替えマクロ
macro index gi "<change-folder>=INBOX<enter>" "Go to inbox"
macro index gt "<change-folder>=+[Gmail]/Trash<enter>" "Go to trash"
macro index gs "<change-folder>=+[Gmail]/送信済みメール<enter>" "Go to sent"
macro index gd "<change-folder>=+[Gmail]/下書き<enter>" "Go to drafts"
問題3: mbsyncでのローカル同期が失敗
症状
mbsync(isync)でメールをローカルに同期しようとしたが、SASL認証エラー:
Error performing SASL authentication step: SASL(-1): generic failure: Unable to find a callback
原因
MacのisyncがXOAUTH2 SASLメカニズムをサポートしていない。
結論
MacでmbsyncのOAuth2同期は非常に困難。 代わりにIMAP直接接続+キャッシュで運用することにしました。
MacのHomebrewでインストールしたisyncはデフォルトでSASLサポートが無効になっており、XOAUTH2プラグインも簡単には導入できません。
第二部:成功した最終手順
教訓:GPGと戦わない
何度もトークンファイルが暗号化される問題に直面し、ようやく気づきました。
mutt-wizardは元々GPG暗号化を前提とした設計になっている。
--encryption-pipe catで暗号化を回避しようとするのではなく、GPG暗号化を受け入れることが正解でした。
手順1: GPG鍵の準備
既存の鍵のパスフレーズを忘れた場合、新しい鍵を作成:
# 古い鍵を削除(必要な場合)
gpg --delete-secret-keys YOUR_OLD_KEY_ID
gpg --delete-keys YOUR_OLD_KEY_ID
# 新しい鍵を作成
gpg --full-generate-key
設定:
- RSA and RSA を選択
- 4096 bits
- 有効期限は 0(無期限)
- 名前とメールアドレスを入力
- 覚えやすいパスフレーズを設定(頻繁に入力することになります)
手順2: トークンファイルの配置場所
mutt-wizard関連の処理の影響を最小限にするため、~/.local/etc/oauth-tokens/に配置:
mkdir -p ~/.local/etc/oauth-tokens
手順3: GPG暗号化を使ってトークンを作成
重要:--encryption-pipeにGPGコマンドを指定します
python3 ~/.config/mutt/mutt_oauth2.py \
--authorize \
--authflow localhostauthcode \
--encryption-pipe 'gpg --encrypt --recipient YOUR_EMAIL@gmail.com' \
--client-id YOUR_CLIENT_ID.apps.googleusercontent.com \
--client-secret YOUR_CLIENT_SECRET \
--provider google \
--email YOUR_EMAIL@gmail.com \
~/.local/etc/oauth-tokens/gmail.tokens
実行すると:
- ブラウザが開いてGoogleログイン
- アクセス権限を許可
- GPGパスフレーズの入力を求められる
- トークンが暗号化されて保存される
手順4: Gmail設定ファイルの作成
4-1. アカウント設定ファイル
nvim ~/.config/mutt/accounts/your-email@gmail.com.muttrc
以下を貼り付け:
# Gmail account settings
set realname = "Your Name"
set from = "your-email@gmail.com"
set smtp_url = "smtps://your-email@gmail.com@smtp.gmail.com:465/"
set imap_user = "your-email@gmail.com"
set folder = "imaps://imap.gmail.com:993"
set spoolfile = "+INBOX"
set postponed = "+[Gmail]/下書き"
set record = "+[Gmail]/送信済みメール"
set trash = "+[Gmail]/ゴミ箱"
# Auto-detect mailboxes
set imap_check_subscribed = yes
# Performance optimizations
set imap_passive = no
set imap_keepalive = 300
set imap_idle = yes
set mail_check = 60
set timeout = 10
# Cache settings
set header_cache = "~/.cache/mutt/headers"
set message_cachedir = "~/.cache/mutt/bodies"
set imap_headers = "X-PRIORITY X-SPAM-STATUS"
# OAuth 2.0 authentication(GPG復号化を使用)
set imap_authenticators = "oauthbearer:xoauth2"
set imap_oauth_refresh_command = "python3 ~/.config/mutt/mutt_oauth2.py --decryption-pipe 'gpg -d' ~/.local/etc/oauth-tokens/gmail.tokens"
set smtp_authenticators = "oauthbearer:xoauth2"
set smtp_oauth_refresh_command = "python3 ~/.config/mutt/mutt_oauth2.py --decryption-pipe 'gpg -d' ~/.local/etc/oauth-tokens/gmail.tokens"
# Editor
set editor = "nvim"
重要なポイント:
--decryption-pipe 'gpg -d'でGPG復号化を指定- 日本語版Gmailの場合、フォルダ名を日本語に変更(下書き、送信済みメール、ゴミ箱)
4-2. メイン設定ファイル
nvim ~/.config/mutt/muttrc
# vim: filetype=neomuttrc
source /usr/local/share/mutt-wizard/mutt-wizard.muttrc
# Editor setting
set editor = "nvim"
# Default account (Gmail)
source ~/.config/mutt/accounts/your-email@gmail.com.muttrc
# Sidebar settings(無効化)
set sidebar_visible = no
# フォルダ切り替えマクロ
macro index gi "<change-folder>=INBOX<enter>" "Go to inbox"
macro index gt "<change-folder>=+[Gmail]/ゴミ箱<enter>" "Go to trash"
macro index gs "<change-folder>=+[Gmail]/送信済みメール<enter>" "Go to sent"
macro index gd "<change-folder>=+[Gmail]/下書き<enter>" "Go to drafts"
macro index ga "<change-folder>=+[Gmail]/すべてのメール<enter>" "Go to all mail"
4-3. キャッシュディレクトリの作成
mkdir -p ~/.cache/mutt/headers ~/.cache/mutt/bodies
4-4. トークンファイルのパーミッション設定
chmod 600 ~/.local/etc/oauth-tokens/gmail.tokens
手順5: 動作確認
トークンが正しく取得できるか確認
# トークンファイルがGPG暗号化されているか確認
file ~/.local/etc/oauth-tokens/gmail.tokens
# 出力例:PGP RSA encrypted session key
# GPGで復号化してトークンを取得
python3 ~/.config/mutt/mutt_oauth2.py --decryption-pipe 'gpg -d' ~/.local/etc/oauth-tokens/gmail.tokens
GPGパスフレーズを入力すると、アクセストークンが表示されればOK。
Neomuttの起動
neomutt
初回起動時:
- GPGパスフレーズの入力を求められます(IMAPとSMTP接続時)
- 少し時間がかかりますが、キャッシュが効いて2回目以降は高速になります
基本的な使い方
Neomuttの起動
neomutt # 私の場合はエイリアスでnm
基本操作
メールリスト:
j/k: 上下移動Enter: メールを開くm: 新規メール作成(nvimが開く)r: 返信d: 削除
フォルダ切り替え(マクロ):
gi: INBOXgt: ゴミ箱gs: 送信済みメールgd: 下書きga: すべてのメール
手動でフォルダ選択:
cキーを押す?と入力- Tab キーでフォルダを選択
- Enter で開く
その他:
q: 終了?: ヘルプ
日本語版Gmailのフォルダ名
日本語版Gmailを使用している場合、フォルダ名は以下のようになります:
set spoolfile = "+INBOX"
set postponed = "+[Gmail]/下書き"
set record = "+[Gmail]/送信済みメール"
set trash = "+[Gmail]/ゴミ箱"
※ 英語版Gmailの場合、フォルダ名は "[Gmail]/Drafts"、"[Gmail]/Sent Mail"、"[Gmail]/Trash" になります。
実際のフォルダ名を確認する方法:
- Neomuttで
cキーを押す ?と入力- Tabキーを押す
- 表示されるフォルダ名を設定に使用
キャッシュの管理
キャッシュは自動的に管理されますが、必要に応じて手動でクリアできます:
# キャッシュサイズを確認
du -sh ~/.cache/mutt
# 古いキャッシュを削除(30日以上前)
find ~/.cache/mutt -type f -mtime +30 -delete
# 全削除
rm -rf ~/.cache/mutt/*
通常は放置で問題ありません(数十MB〜数百MB程度)。
Google Cloudの料金について
今回の設定で使用したGoogle Cloud Platformのサービスは完全無料です。
- OAuth 2.0クライアントID: 無料
- Gmail API: 個人使用の範囲内で無料
- テスト中のアプリ: 100ユーザーまで無料
クレジットカードの登録を求められますが、自分だけが使うテストアプリなので一切課金されません。
念のため、Google Cloud Consoleの「お支払い」で予算アラートを設定することもできます。
個人使用の範囲内では無料です。Gmail APIには1日あたり10億クォータ単位の無料枠がありますが、個人的なメール使用では到達することはまずありません。
最終的なファイル構成
~/.config/mutt/
├── muttrc # メイン設定
├── accounts/
│ └── your-email@gmail.com.muttrc # Gmailアカウント設定
└── mutt_oauth2.py # OAuth2スクリプト
~/.local/etc/oauth-tokens/
└── gmail.tokens # OAuthトークン(GPG暗号化)
~/.cache/mutt/
├── headers/ # ヘッダーキャッシュ
└── bodies/ # メッセージキャッシュ
まとめ
MacでMutt-wizard + NeomuttでGmailをOAuth 2.0で使えるようになりました!
達成したこと:
- ✅ Gmail OAuth 2.0認証(GPG暗号化で安定動作)
- ✅ Neomuttで快適にメール閲覧・送信
- ✅ nvimでメール作成
- ✅ マクロで素早いフォルダ切り替え
- ✅ キャッシュで高速化
断念したこと:
- ❌ mbsyncでのローカル同期(MacではOAuth2対応が困難)
- ❌ サイドバーの使用(IMAP直接接続では機能しない)
重要な教訓:
- mutt-wizardの設計思想(GPG暗号化)と戦わず、それに従うことが成功の鍵
--encryption-pipe catで暗号化を回避しようとするのは間違いだった- GPGパスフレーズは覚えやすいものにする(頻繁に入力する)
ターミナルでメールを読み書きできる環境が整い、とても満足しています!