Read O365 library emails with python


I am making an application where I have to read emails from my inbox, Outlook.

For this I am using the O365 library with python.

The authentication is done correctly, then I try to get the folder where I have the emails:

inbox = mailbox.get_folder(folder_name='Bandeja de entrada')

I perform the query, with the created_date_time parameter:

query_email = mailbox.new_query()
query_email = query_email.on_attribute('created_date_time').\
            greater(datetime(from_date_time.year, from_date_time.month,\

And I launch the query and read the results:

for message in inbox.get_messages(limit=999,

But the problem is that he reads me very few or none and only from the folder that I indicate at the beginning.

What I want you to do is read the new and old emails, even if they are already read, from the date I indicate.


To send and read mail you can use:

  • Mail.ReadWrite
  • Mail.Send
  • User.Read

You need to log in to get the access token that will guarantee you to use the resources.

To authenticate (log in) you can use different authentication interfaces. In the following examples, we'll use the console-based interface, but you can use either.

When authenticating on behalf of a user:

Important: In case you cannot ensure client secrecy, you can use 'public' authentication flow type, which only requires client identification.

Instantiates an Account object with the credentials (client id and client secret).

Call account.authenticate, and pass in the scopes you want (the ones you added earlier in the app registration portal).

Note: When using "on behalf of a user" authentication, you can pass scopes to the Account init method or the authentication method. Either way it is correct.

You can pass "protocol scopes" (like: " ") to the method or use " scope helpers " like ("message_all"). If you pass protocol scopes, the account instance must be initialized with the same protocol that the scopes use. By using scope helpers, you can abstract the protocol from the scopes and let this library work for you.

Lastly, you can mix and match "protocol scopes" with "scope helpers". Go to the procotol section to know more about them.

For example (following the permissions above added):

from O365 import Account
credentials = ('my_client_id', 'my_client_secret')

# the default protocol will be Microsoft Graph
# the default authentication method will be "on behalf of a user"

account = Account(credentials)
if account.authenticate(scopes=['basic', 'message_all']):

# 'basic' adds: 'offline_access' and ''
# 'message_all' adds: '' and ''

When using the "on behalf of the user" authentication method, this method call will print a URL that the user must visit in order to consent to the application's required permissions.

The user must then visit this URL and consent to the application. When consent is given, the page will redirect to: " " by default (you can change this) with a URL query parameter called 'code'.

The user then needs to copy the URL of the resulting page and paste it back into the console. The method will return True if the login attempt was successful.

When authenticating with your own identity:

An instance of an Account object with the credentials (client ID and client secret), specifying the auth_flow_type parameter of "credentials" . You must also provide a 'tenant_id'. You do not need to specify any scopes.

Call account.authenticate. This call will request a token from you and store it in the backend. No user interaction is required. The method will store the token in the backend and return True if the authentication was successful.

For example:

from O365 import Account

credentials = ('my_client_id', 'my_client_secret')

# the default protocol will be Microsoft Graph

account = Account(credentials, auth_flow_type='credentials', tenant_id='my-tenant-id')
if account.authenticate():

At this point, you will have a stored access token that will provide valid credentials when using the API.

The access token only lasts 60 minutes, but the app attempt will automatically request new access tokens.

When using the "on behalf of a user" authentication method, this is achieved via refresh tokens (if and only if you added the "offline_access" permission), but note that a refresh token only lasts 90 days. So you either need to use it before or you'll need to request a new access token again (the user doesn't need a new consent, just a login). If your application needs to run for more than 90 days with no user interaction and no API interaction, then you should implement a periodic call to Connection.refresh_token before the 90 days have passed.

Be careful: the access (and refresh) token must remain protected from unauthorized users.

Under the "on behalf of a user" authentication method, if you change the requested scope, the current token will not work and you will need the user to consent again in the application to gain access to the new requested scopes.

Scroll to Top