I have a python script that used to login to an outlook inbox:
from imaplib import IMAP4_SSL
imap = IMAP4_SSL("outlook.office365.com")
imap.login("user", "password")
It now fails with an error:
Traceback (most recent call last):
File "imap.py", line 4, in <module>
imap.login("user", "password")
File "/usr/lib/python3.8/imaplib.py", line 603, in login
raise self.error(dat[-1])
imaplib.error: b'LOGIN failed.'
Microsoft has disabled basic authentication for Exchange Online. How should I authenticate now that basic auth has been deprecated?
In order to authenticate with OAUTH2 you need an existing app registration in Azure. I am assuming you already have this set up.
NOTE: An admin may need to approve the permission. They also may need to set up the Service Principal (there is one unclear step to be aware of).
from urllib.parse import urlencode
import requests
tenant = "Directory (tenant) ID"
url = f"https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token"
payload = urlencode({
"client_id": "Application (client) ID",
"client_secret": "Secret Value",
"scope": "https://outlook.com/.default",
"grant_type": "client_credentials"
})
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
response = requests.request("POST", url, headers=headers, data=payload)
access_token = response.json()["access_token"]
NOTE: Scope is important! I had to use https://outlook.com/.default
. I've seen some documentation use https://graph.microsoft.com/.default
or https://ps.outlook.com/.default
, neither of which have access to authenticating with the IMAP server.
Change the imap.login
call to imap.authenticate
:
imap.authenticate(
"XOAUTH2",
lambda _: f"user={email}\1auth=Bearer {access_token}\1\1".encode()
)
The second parameter expects bytes, so I encode
the formatted string.