newline

Table of Contents

  1. Set up isync
    1. OAUTH2 script
  2. Set up msmtp
  3. Conclusion

Using Microsoft Office365 with Neomutt (+ isync + msmtp)

Guide, Shell

February 04, 2022

My university switched its Microsoft Office365 email system to just “modern authentication”, and I suspect a lot of other companies using Microsoft’s stack did the same around this time. What that means is, unless I use what’s deemed a “modern application”, I won’t be able to access my email. However, I like my email the way I have it: on the command line, scriptable, and synced offline. It took some time, but I figured out how to make my setup work with Office365 (fortunately, what Microsoft calls “modern authentication” is just marketing speak for OAUTH2); this post explains the steps. I’m using macOS, but the same can be achieved with similar steps on GNU/Linux (though not all steps might be necessary). I use the newest versions of all tools, installed via Homebrew unless I explicitly say otherwise.

Set up isync

isync is what handles email retrieval (the binary is named mbsync, and the program is entirely unrelated to Apple, despite what the name might imply). First, I cloned its source code, because I needed to make some changes to it:

git clone https://git.code.sf.net/p/isync/isync isync

Then, I applied the following patch, discussed in this Github issue:

diff --git a/src/drv_imap.c b/src/drv_imap.c
index c5a7aed..20f2e6a 100644
--- a/src/drv_imap.c
+++ b/src/drv_imap.c
@@ -2195,6 +2195,7 @@ static sasl_callback_t sasl_callbacks[] = {
 	{ SASL_CB_USER,     NULL, NULL },
 	{ SASL_CB_AUTHNAME, NULL, NULL },
 	{ SASL_CB_PASS,     NULL, NULL },
+	{ SASL_CB_OAUTH2_BEARER_TOKEN, NULL, NULL },
 	{ SASL_CB_LIST_END, NULL, NULL }
 };

@@ -2212,6 +2213,7 @@ process_sasl_interact( sasl_interact_t *interact, imap_server_conf_t *srvc )
 			val = ensure_user( srvc );
 			break;
 		case SASL_CB_PASS:
+		case SASL_CB_OAUTH2_BEARER_TOKEN:
 			val = ensure_password( srvc );
 			break;
 		default:

I used the following commands to compile and install isync (after removing the version I installed from Homebrew; note that you need openssl installed via Homebrew):

./configure CFLAGS='-I/usr/local/opt/openssl/include' CPPFLAGS='-I/usr/local/opt/openssl/include' LDFLAGS='-L/usr/local/opt/openssl/lib' --with-ssl=/usr/local/opt/openssl\@1.1/
make
sudo make install

OAUTH2 script

Next, I downloaded the mutt_oauth2 script, which is responsible for generating OAUTH2 tokens. In this script, I changed the values registrations.microsoft.client_id and registrations.microsoft.client_secret to the ones used by Thunderbird; those are publicly available on one of Mozilla’s pages in the array associated with login.microsoftonline.com.

I used this command to authorize my account, using the localhostauthcode flow:

./mutt_oauth2.py my.email@domain.com.tokens --verbose --authorize

The file my.email@domain.com.tokens then contains a PGP-encrypted OAUTH2 token, which can be tested with:

./mutt_oauth2.py my.email@domain.com.tokens --verbose --test

I moved the token file to a better location, and the mutt_oauth2.py script to a location in my PATH.

Finally, I made two changes in the mbsyncrc config file. For the Office365 account, I:

Update 2024-02-10: Samuel pointed out that Mozilla have switched Thunderbird to desktop client auth. I updated the links in this post to point directly to the commit with the client secret still present. As I do not have a Microsoft account anymore, I cannot verify it still works. However, Samuel has been able to continue using the mutt_oauth2.py script with the devicecode flow.

Set up msmtp

I use msmtp to send email. Fortunately, the changes to its config file were much simpler than for isync.

For the Office365 account, I:

Conclusion

After these changes, the account works perfectly with my setup. If something is unclear, the sidebar lists all of the webpages I used for reference.

Unfortunately, I don’t yet have a solution for mobile. K-9 mail doesn’t support OAUTH2, though there is a pull request open. I tried FairEmail, but an admin needs to allow access for FairEmail, and apparently for ‘security’ they only allow Outlook. So on mobile, I’ll have to stick with the Outlook web app in a private browser tab until something better shows up (and if you have suggestions, I’m happy to hear them!) – I’m not installing proprietary garbage like Outlook or Gmail apps that scan your messages to ‘improve’ advertising.

Update: on mobile, I now use Shelter to create and manage an isolated work profile. This uses AOSP’s work profile implementation, and means that apps installed in the work profile don’t have access to data from the personal profile (I also keep the work profile disabled most of the time). On top of that, I use TrackerControl to whitelist network requests, so I can limit tracking to some extent. It’s nowhere near as good as being able to use something like K-9 or FairEmail, but this setup is ok for me.