Benjamin Gorman
Benjamin Gorman

Reputation: 370

Accessing Exchange inbox using exchangelib from Python with oauth

Since Microsoft has now dropped support for accessing an Exchange mailbox using basic authentication, I've had to upgrade some code to use oauth based access to the mailbox instead.

I've setup an Azure AD app following these docs:

Now I'd like to access emails from the mailbox using exchangelib and exchangelib.OAuth2Credentials

Here's the code I'm using:

from exchangelib import Account, OAuth2Credentials

AZURE_CLIENT_ID = "MY_CLIENT_ID"
AZURE_TENANT_ID = "MY_TENANT_ID"
AZURE_CLIENT_CREDENTIAL = "MY_CLIENT_CREDENTIAL"
MY_EMAIL = "[email protected]"

credentials = OAuth2Credentials(
  client_id=AZURE_CLIENT_ID, client_secret=AZURE_CLIENT_CREDENTIAL, tenant_id=AZURE_TENANT_ID
)

account = Account(primary_smtp_address=MY_EMAIL, credentials=credentials, autodiscover=True)

for item in account.inbox.all().order_by('-datetime_received')[:100]:
  print(item.subject, item.sender, item.datetime_received)

However I'm getting an error saying The SMTP address has no mailbox associated with it:

Traceback (most recent call last):
  File "exchangelib_test.py", line 19, in <module>
    account = Account(primary_smtp_address=MY_EMAIL, credentials=credentials, autodiscover=True)
  File "/home/me/.local/lib/python3.6/site-packages/exchangelib/account.py", line 119, in __init__
    email=primary_smtp_address, credentials=credentials, auth_type=auth_type, retry_policy=retry_policy
  File "/home/me/.local/lib/python3.6/site-packages/exchangelib/autodiscover/discovery.py", line 114, in discover
    ad_response = self._quick(protocol=ad_protocol)
  File "/home/me/.local/lib/python3.6/site-packages/exchangelib/autodiscover/discovery.py", line 201, in _quick
    return self._step_5(ad=ad)
  File "/home/me/.local/lib/python3.6/site-packages/exchangelib/autodiscover/discovery.py", line 531, in _step_5
    ad.raise_errors()
  File "/home/me/.local/lib/python3.6/site-packages/exchangelib/autodiscover/properties.py", line 313, in raise_errors
    raise ErrorNonExistentMailbox('The SMTP address has no mailbox associated with it')
exchangelib.errors.ErrorNonExistentMailbox: The SMTP address has no mailbox associated with it

Does anyone have an idea what might be going wrong here? The SMTP address definitely does exist and is an Exchange mailbox which I can log in to and view via Outlook.

Upvotes: 0

Views: 3405

Answers (2)

AJain2810
AJain2810

Reputation: 435

For using the Azure App based OAuth flow:

from exchangelib import OAuth2Credentials

credentials = OAuth2Credentials(
  client_id='Azure_APP_IS', client_secret='AZURE_APP_SECRET', tenant_id='AZURE_TENANT_ID', , identity=Identity(primary_smtp_address='[email protected]')
)

And for accessing the account using the same:

my_account = Account(
  primary_smtp_address='[email protected]', credentials=credentials,
  autodiscover=True, access_type=IMPERSONATION
)

Upvotes: 0

Glen Scales
Glen Scales

Reputation: 22032

If your using the client credentials flow then you will also need to use Impersonation access_type=IMPERSONATION eg

account = Account(primary_smtp_address=MY_EMAIL, credentials=credentials, autodiscover=True, access_type=IMPERSONATION)

generally with Office365 you don't want to use Autodiscover as the endpoint is always outlook.office365.com there is a sample of bypassing that in the samples page https://ecederstrand.github.io/exchangelib/ eg

config = Configuration(server='outlook.office365.com', 
credentials=credentials)
account = Account(primary_smtp_address='[email protected]', config=config,
              autodiscover=False, access_type=IMPERSONATION)

Upvotes: 2

Related Questions