Configuring mutt (neomutt) for IMAP/SMTP access to O365 Exchange
Office 365 Exchange requires XOauth2 tokens to authenticate via IMAP and SMTP. Mutt/Neomutt can use this form of authentication with the mutt_oauth2.py script
Pre-requisites:
- A working GPG Public/Private keypair and local gpg installation. This is only used to encrypt the tokens locally. You can use an existing one or create a new one for this purpose, but I won’t go into how to do that here.
- The mutt_oauth2.py script
- A UW O365 Exchange account
- mutt/neomutt
Steps:
The instructions in the mutt_oauth2.py.README have a pretty complete listing of steps, but they do need to be tweaked a little for access to UW’s Exchange system.
Create an Entra ID Application
- Log into Microsoft Entra ID (Sometimes called Azure AD in tutorials)
- Click ‘App Registrations’ from the left menu
- Click ‘New Registration’ and give your app a descriptibe name like ’neomutt.’ Leave the ‘Supported account types’ at it’s default. Under Redirect URI, select ‘Public client/native (mobile & desktop)’ and enter “http://localhost/” for the URI path.
- Click ‘Register’
- On your new App’s overview page, take note down the ‘Application (client) ID’
- Click ‘API Permissions’
- Click ‘Add a permission,’ Select the large ‘Microsoft Graph’ option, the click ‘Delegated permissions.’ Search and add the following permissions:
- User.Read
- IMAP.AccessAsUser.All
- SMTP.Send
- offline_access
Modify the mutt_oauth2.py script
The script by default uses the /common/ Microsoft Entra endpoint. It will need to be edited slightly to point the UW endpoints
Change the following lines:
'microsoft': {
'authorize_endpoint': 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
'devicecode_endpoint': 'https://login.microsoftonline.com/common/oauth2/v2.0/devicecode',
'token_endpoint': 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
'redirect_uri': 'https://login.microsoftonline.com/common/oauth2/nativeclient',
'tenant': 'common',
To read as follows:
'microsoft': {
'authorize_endpoint': 'https://login.microsoftonline.com/uw.edu/oauth2/v2.0/authorize',
'devicecode_endpoint': 'https://login.microsoftonline.com/uw.edu/oauth2/v2.0/devicecode',
'token_endpoint': 'https://login.microsoftonline.com/uw.edu/oauth2/v2.0/token',
'redirect_uri': 'http://localhost/',
'tenant': 'uw.edu',
Note: for each of the first three URLs and the ’tenant’ entry, ‘common’ was replaced with ‘uw.edu’ Additionally, the ‘redirect_uri’ was changed to match the URI we entered when we created our Entra App: https://localhost/
Registering your auth tokens with the mutt_oauth2.py script
Manually run the following command:
./mutt_oauth2.py --authorize --provider microsoft --authflow authcode --email <your@uw.email> --client-id <your-application-client-id> <your@uw.email>.tokens
The script should spit out a long URL, click the link, or open that URL in your web browser. At this point you will be prompted to log in with your UW Microsoft account. Additionally you will recieve a prompt to allow this app to view your account and send/recieve email. Click Approve.
If this step is successful, your browser will redirect to a http://localhost/ URL that will give you an error. This is ok, the information you need is included in that URL. From the browser address bar copy everything between ‘code=’ and ‘$state…’ Paste that string into the script window where it should be waiting patiently for a code. You should also be able to use one of the other auth flows, there is more information in the README.
The script will authenticate and spit out a long string. You can ignore that. To validate that everything went smoothly, run:
./mutt_oauth2.py --verbose --test <your@uw.email>.tokens
You should see messages that authentication succeeded for each mail protocol
Updating muttrc
Update your muttrc/neomuttrc with the following information:
set imap_user="<your@uw.email>"
set folder="imap://outlook.office365.com/"
set smtp_url="smtp://${imap_user}@smtp.office365.com:587/"
set imap_authenticators="oauthbearer:xoauth2"
set imap_oauth_refresh_command="/path/to/mutt_oauth2.py <your@uw.email>.tokens"
set smtp_authenticators=${imap_authenticators}
set smtp_oauth_refresh_command=${imap_oauth_refresh_command}