O365 / python-o365

A simple python library to interact with Microsoft Graph and Office 365 API
Apache License 2.0
1.6k stars 411 forks source link

outlook SMTP auth using XOAUTH #853

Open Krukosz opened 1 year ago

Krukosz commented 1 year ago

This is not a issue, but a solution/discussion.

I had to switch off basic auth to Outlook365' SMTP, because Microsoft turned off it at all. I use smtplib for sending emails (sending emails with MS Graph has not implemented multipart MIME).

Micosoft shows how to sign with legacy protocols (SMTP, IMAP, POP3) here.

Basically: i need to use token generated witin Account.authenticate method and make "AUTH" command to smtp.

Here's my code snippet:

import smtplib
import base64
import os, os.path
from O365 import Account
from O365 import FileSystemTokenBackend

client_id = 'my_client_id'
client_secret = 'my_secret'
tenant_id = 'my_tenant_id'

credentials = (client_id, client_secret)

scopes = ['offline_access', 'https://outlook.office.com/SMTP.Send']
token_backend = FileSystemTokenBackend(token_path=os.environ['HOME'], token_filename='_o365_token_smtp')

account = Account(credentials, scopes=scopes, token_backend=token_backend, tenant_id=tenant_id)
if not account.is_authenticated:
    redirect_uri="my_redirect_uri"
    account.authenticate(redirect_uri=redirect_uri)
else:
    print('logged in!')
    smtp_conn = smtplib.SMTP('smtp.office365.com', 587)
    smtp_conn.set_debuglevel(1)
    userName = 'microsoft_username'

    tb = account.con.token_backend.load_token()
    accessToken = tb['access_token']

    xoauth_string = 'user={0}\1auth=Bearer {1}\1\1'.format(userName, accessToken)
    b64_xoauth = base64.b64encode(xoauth_string.encode('utf-8'))
    smtp_conn.ehlo()
    smtp_conn.starttls()
    smtp_conn.ehlo()
    smtp_conn.docmd('AUTH', 'XOAUTH2 {0}'.format(b64_xoauth.decode('utf8')))

    smtp_conn.sendmail('address_from@mail', 'address_to@mail', smtp_message')
    smtp_conn.quit()

NOTE: If you will have 5.7.3 Authentication unsuccessful error, make sure to call explicitly scope https://outlook.office.com/SMTP.Send with Outlook domain, as I did in above code.

Microsoft documentation: here

Similar issues: 1 and 2

yjy123123 commented 1 year ago

I don't know why it always has error 5.7.3 Authentication unsuccessful. And I have set the correct scope.

Krukosz commented 1 year ago

@yjy123123 try either login or login@domain.com You must have app with SMTP.Send scope permission