Try   HackMD

Mutt with OAuth2

contributed by < linD026 >

tags: kernel-tools

Google registration

Reference : mutt/contrib/mutt_oauth2.py.README

Go to console.developers.google.com, and create a new project. The name doesn't
matter and could be "mutt registration project".

  • Go to Library, choose Gmail API, and enable it
  • Hit left arrow icon to get back to console.developers.google.com
  • Choose OAuth Consent Screen
    • Choose Internal for an organizational G Suite
    • Choose External if that's your only choice
    • For Application Name, put for example "Mutt"
    • Under scopes, choose Add scope, scroll all the way down, enable the "https://mail.google.com/" scope
    • Fill out additional fields (application logo, etc) if you feel like it (will make the consent screen look nicer)
  • Back at console.developers.google.com, choose Credentials
  • At top, choose Create Credentials / OAuth2 client iD
    • Application type is "Desktop app"

Edit the client_id (and client_secret if there is one) into the
mutt_oauth2.py script.

NOTE
It needs to add the account to the Test user ( at "OAuth consent screen::Test users"").
Otherwise, we cannot get the code in next step.


Gnu Privacy Guard (gpg)

$ gpg --gen-key

First, we set Name and Email. We can simply set Name as "My mutt_oauth2 token store" and let the email empty. It will generate:

igpg: /home/user/.gnupg/trustdb.gpg: trustdb created
gpg: key 2856933BAECE4525 marked as ultimately trusted
gpg: directory '/home/user/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/home/user/.gnupg/openpgp-revocs.d/BE294513C874525DE247E452428759334678E5C25.rev'
public and secret key created and signed.

pub   rsa3072 2022-06-20 [SC] [expires: 2024-06-19]
      BE29B13457465DE234E44122856933BAEC8E4525
uid                      My mutt_oauth2 token store
sub   rsa3072 2022-06-20 [E] [expires: 2024-06-19]

mutt_oauth2.py

mutt_oauth2.py needs Python >= 3.7 to work.

After that, edit mutt_oauth2.py:

  • From gpg
    • YOUR_GPG_IDENTITY
  • From google
    • client_id
    • client_secret
ENCRYPTION_PIPE = ['gpg', '--encrypt', '--recipient', 'My mutt_oauth2 token store']
DECRYPTION_PIPE = ['gpg', '--decrypt']

registrations = {
    'google': {
        'authorize_endpoint': 'https://accounts.google.com/o/oauth2/auth',
        'devicecode_endpoint': 'https://oauth2.googleapis.com/device/code',
        'token_endpoint': 'https://accounts.google.com/o/oauth2/token',
        'redirect_uri': 'urn:ietf:wg:oauth:2.0:oob',
        'imap_endpoint': 'imap.gmail.com',
        'pop_endpoint': 'pop.gmail.com',
        'smtp_endpoint': 'smtp.gmail.com',
        'sasl_method': 'OAUTHBEARER',
        'scope': 'https://mail.google.com/',
        'client_id': '10072841202637-j2bvitf3k3j12do40ja2dsjg9nigdasdec2.apps.googleusercontent.com',
        'client_secret': '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oj',
    },

Then, export GPG_TTY=$(tty).

Now, we can excute the script:

$ ./mutt_oauth2.py user@gmail.com.tokens --verbose --authorize

Here is the first command, it will generate the tokens file.
Select google, authcode, and paste the code from the website.
When finished the command, it will have the access and refresh tokens.

access token will be expired.
So it needs the refresh token to get the access token.

$ ./mutt_oauth2.py user@gmail.com.tokens --verbose --test
$ ./mutt_oauth2.py user@gmail.com.tokens --verbose --debug --test

For the debugging.

$ ./mutt_oauth2.py user@gmail.com.tokens

It will return the access token.


Add to mutt config

set imap_authenticators="oauthbearer:xoauth2"
set imap_oauth_refresh_command="/path/to/script/mutt_oauth2.py /path/to/token/${imap_user}.tokens"
set smtp_authenticators=${imap_authenticators}
set smtp_oauth_refresh_command=${imap_oauth_refresh_command}

Then done. We can use Mutt to access gmail.

NOTE
To fix the mutt cannot execute every reboot.

    Authenticating (OAUTHBEARER)...You must run script with "--authorize" at least

You needs to specific the path:

./path/to/script/mutt_oauth2.py /path/to/token/${imap_user}.tokens

Some detail about Mutt

tips

For how to read emails in Mutt, see help ( press ?).
Like < and > can scroll up and down one line, / for searching the word, q for quit.

  • Show the email you sent in Mutt.
    • Enter c and ?, then choose the Gmail, All Mail or other IMAP that have your email.
    • Otherwise, you can just cc yourself when you are sending the email.
  • When you want to reply all the address, plesse use g for group reply (reply all).
  • Save the email to the local file. Hit v to open the attachments and s to save.

My configuration

set imap_user = 'user@gmail.com'
set imap_pass = ''
set spoolfile = imaps://imap.gmail.com/INBOX
set folder = imaps://imap.gmail.com/
# Do NOT save sent messages on the server.
# If your client is sending mail through Gmail's SMTP server,
# your sent messages will be automatically copied to
# the [Gmail]/Sent Mail folder.
set record="imaps://imap.gmail.com/[Gmail]/Sent Mail"
# disable mutt's storing of all sent mail
set copy = no
set postponed="imaps://imap.gmail.com/[Gmail]/Drafts"
set mbox="imaps://imap.gmail.com/[Gmail]/All Mail"

# ================  oauth2  ====================

set imap_authenticators="oauthbearer:xoauth2"
set imap_oauth_refresh_command="~/.mutt/mutt_oauth2.py ~/.mutt/${imap_user}.tokens"
set smtp_authenticators=${imap_authenticators}
set smtp_oauth_refresh_command=${imap_oauth_refresh_command}

# ================ No authenticators available - BUG ===============
# With Homebrew in MacOS
set smtp_authenticators = 'gssapi:login'

# ================  SMTP  ====================
set smtp_url = "smtp://user@smtp.gmail.com:587/"
set smtp_pass = ${imap_pass}
set ssl_force_tls = yes # Require encrypted connection

# ================  Composition  ====================

set editor = "vim"
set edit_headers = yes  # See the headers when editing
set charset = UTF-8     # value of $LANG; also fallback for send_charset
# Sender, email address, and sign-off line must match
unset use_domain        # because joe@localhost is just embarrassing
set realname = "MY-NAME"
set from = "user@gmail.com"
set use_from = yes

set crypt_replysign = yes
set crypt_verify_sig = yes

# ============== Mail ================

set sort=threads
set timeout=10

# ============== Color ===============

color normal  white default
color attachment brightyellow default
color hdrdefault cyan default
color indicator black cyan
color markers brightred default
color quoted  green default
color signature cyan default
color status  brightgreen blue
color tilde blue default
color tree  red default

color index red default ~P
color index red default ~D
color index magenta default ~T

color header brightgreen default ^From:
color header brightcyan default ^To:
color header brightcyan default ^Reply-To:
color header brightcyan default ^Cc:
color header brightblue default ^Subject:

color body  brightred default [\-\.+_a-zA-Z0-9]+@[\-\.a-zA-Z0-9]+
# identifies email addresses

color body  brightblue default (https?|ftp)://[\-\.,/%~_:?&=\#a-zA-Z0-9]+
# identifies URLs

More easy way to do it

Set application password to imap_pass.
You can set the password in https://myaccount.google.com/security .
Then, here you go. :)

NOTE
With Homebrew, you need to add following setting to avoid No authenticators available problem.

set smtp_authenticators = 'gssapi:login'

From https://github.com/Homebrew/legacy-homebrew/issues/33419


Fix your mutt

https://lwn.net/Articles/924822/