I am trying to build an application that sends emails from my Microsoft office email account, in Python using SMTP for sending with OAuth2 for authentication. The authentication is not working, I am getting reply: retcode (535); Msg: b'5.7.3 Authentication unsuccessful [LO2P265CA0061.GBRP265.PROD.OUTLOOK.COM]'
I have created an AAD application on azure and downloaded the example flask app that is offered there after setting up the credentials, which I understand is just this repo
I have used this app (downloaded from the AAD portal with my secret in it) and tried to use the given token for SMTP authentication, using the information from
Logging in with my office email account works and the /graphcall works as well. However the SMTP authentication is not working, I am receiving reply: retcode (535); Msg: b'5.7.3 Authentication unsuccessful [LO2P265CA0061.GBRP265.PROD.OUTLOOK.COM]' from it.
The Scope of the token that I am asking for is SCOPE = ["User.ReadBasic.All", "https://outlook.office.com/SMTP.Send"] and the app has SMTP.send turned on in the config file
Here is a class extending smtplib.SMTP that I have written based on those:
import smtplib
import base64
class MicrosoftSMTP(smtplib.SMTP):
def __init__(self, host="smtp.office365.com", port=587, **kwargs):
super().__init__(host=host, port=port, **kwargs)
@staticmethod
def encode_auth_token(username, token):
just_a_str = f"user={username}\x01auth=Bearer {token}\x01\x01"
xoauth2_token = base64.b64encode(just_a_str.encode())
return xoauth2_token
def authenticate(self, username, token):
self.helo()
# first step, we
code, msg = self.docmd("auth", "XOAUTH2")
if code != 334:
raise Exception(msg.decode())
# send the token
self.send(self.encode_auth_token(username, token))
and the code to connect with the credentials from the app here, and adding a page where I display the token json for a sanity check:
@app.route("/send_to_self")
def send_to_self():
token = _get_token_from_cache(app_config.SCOPE)
if not token:
return redirect(url_for("login"))
# connect to the server
connection = MicrosoftSMTP()
connection.set_debuglevel(True) # for output
connection.starttls()
connection.authenticate(
# same as session["user"]["preferred_username"]
token["id_token_claims"]["preferred_username"],
token["access_token"],
)
# ... would write an email here with connection.sendmail( ... )
connection.quit()
return render_template(
"send_to_self.html",
data=token,
data_session=session["flow"],
data_user=session["user"],
)
The authentication is failing, here is the full log:
send: 'ehlo 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa\r\n'
reply: b'250-LO2P265CA0516.outlook.office365.com Hello [<A.GENERAL.IP>]\r\n'
reply: b'250-SIZE 157286400\r\n'
reply: b'250-PIPELINING\r\n'
reply: b'250-DSN\r\n'
reply: b'250-ENHANCEDSTATUSCODES\r\n'
reply: b'250-STARTTLS\r\n'
reply: b'250-8BITMIME\r\n'
reply: b'250-BINARYMIME\r\n'
reply: b'250-CHUNKING\r\n'
reply: b'250 SMTPUTF8\r\n'
reply: retcode (250); Msg: b'LO2P265CA0516.outlook.office365.com Hello [<A.GENERAL.IP>]\nSIZE 157286400\nPIPELINING\nDSN\nENHANCEDSTATUSCODES\nSTARTTLS\n8BITMIME\nBINARYMIME\nCHUNKING\nSMTPUTF8'
send: 'STARTTLS\r\n'
reply: b'220 2.0.0 SMTP server ready\r\n'
reply: retcode (220); Msg: b'2.0.0 SMTP server ready'
send: 'helo 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa\r\n'
reply: b'250 LO2P265CA0516.outlook.office365.com Hello [<A.GENERAL.IP>]\r\n'
reply: retcode (250); Msg: b'LO2P265CA0516.outlook.office365.com Hello [<A.GENERAL.IP>]'
send: 'auth XOAUTH2\r\n'
reply: b'334 \r\n'
reply: retcode (334); Msg: b''
send: b'dX......EB'
send: 'quit\r\n'
reply: b'535 5.7.3 Authentication unsuccessful [LO2P265CA0516.GBRP265.PROD.OUTLOOK.COM]\r\n'
reply: retcode (535); Msg: b'5.7.3 Authentication unsuccessful [LO2P265CA0516.GBRP265.PROD.OUTLOOK.COM]'
things I have cheeked:
- we have SMTP allowed for this mailbox
- the token has the SMTP allowed
- the XOAUTH2 token encoder's output matches that of the example on the website
FYI the token data looks like this, with the tokens and username removed
{
"access_token": "ey<...>aw",
"client_info": "ey<...>In0",
"expires_in": 3599,
"ext_expires_in": 3599,
"id_token": "ey<...>jQ",
"id_token_claims": {
"aud": "8<...>9",
"exp": 1634319637,
"iat": 1634315737,
"iss": "https://login.microsoftonline.com/5<...>1/v2.0",
"name": "<Name of the user>",
"nbf": 1634315737,
"nonce": "c1<...>d0",
"oid": "cd<...>1b",
"preferred_username": "user.name@company.com",
"rh": "0.A<...>As.",
"sub": "2w<...>ww",
"tid": "50<...>31",
"uti": "8W<...>AA",
"ver": "2.0"
},
"refresh_token": "0.A<...>4Y",
"scope": "openid profile SMTP.Send User.ReadBasic.All email",
"token_type": "Bearer"
}