The goal of this project is to look through a mailbox and detach attachments based on subject, sender, has attachments and is read. For this to work, each email that is found must be set to read which it is being processed. I am using the O365 library from python to access the mailbox and search the mailbox and this works great, however, I cannot seem to mark emails as read as they are being processed. I have created an app in the Azure portal and given it the permissions / scopes required by the request as seen through Microsoft Graph Explorer, but the error persists. The code is as follows: (------- represent ids and keys that are private though theoretically correct. If the issue could be with one of these values, that would be just as helpful to know)
from O365 import Account
import datetime
today = str(datetime.date.today())
today = '2022-10-18'
def clean(text):
# clean text for creating a folder
return "".join(c if c.isalnum() else "_" for c in text)
credentials = ('------------', '------------')
account = Account(credentials, auth_flow_type='credentials', tenant_id='---------------')
if account.authenticate():
print('Authenticated!')
mb = account.mailbox(resource='---------')
#inbox = mb.inbox_folder()
query = mb.new_query().search('isRead:false AND subject:Your export Paychex Flex Time Export -
Current Pay Period is ready AND from:[email protected] ([email protected])
hasattachment:yes')
messages = mb.get_messages(limit=25, query=query) #gets queried messages
messages = list(messages) #converts generator to list for accessing
message = messages[0] #get the first email
# SOLUTION ATTEMPT 1 - set read parameter and save changes
print(message.is_read) #shows that mail is unread
message.is_read = True #sets is_read to True to read the email
print(message.is_read) #shows that the mail in now read
message.save_message() # creates 403 forbidden for url / Access denied error
# SOLUTION ATTEMPT 2 - call mark_as_read on message
message.mark_as_read() # creates 403 forbidden for url / Access denied error
The Following is the full error message with the account name removed:
https://graph.microsoft.com/v1.0/users/-----------/messages/AQMkAGQwMTIzZjUxLWM2ZDEtNDZmYy1iNzg2LTYwODllYzEyYTcwOQBGAAADKEW4unIZakyZqYIBvTk6zwcANBYieEfG5k6Qg3ECuGo5mQAAAgEMAAAANBYieEfG5k6Qg3ECuGo5mQABQw79mgAAAA== | Error Message: Access is denied. Check credentials and try again.
File "C:\Python39-32\Lib\site-packages\O365\connection.py", line 708, in _internal_request
response.raise_for_status() # raise 4XX and 5XX error codes.
File "C:\Python39-32\Lib\site-packages\requests\models.py", line 1021, in raise_for_status
raise HTTPError(http_error_msg, response=self)
During handling of the above exception, another exception occurred:
File "C:\Python39-32\Lib\site-packages\O365\connection.py", line 762, in _internal_request
raise HTTPError('{} | Error Message: {}'.format(e.args[0], error_message), response=response) from None
File "C:\Python39-32\Lib\site-packages\O365\connection.py", line 800, in oauth_request
return self._internal_request(self.session, url, method, **kwargs)
File "C:\Python39-32\Lib\site-packages\O365\connection.py", line 844, in patch
return self.oauth_request(url, 'patch', data=data, **kwargs)
File "C:\Python39-32\Lib\site-packages\O365\message.py", line 918, in save_message
response = self.con.patch(url, data=data)
File "C:\Python39-32\PaychexEmailReader_v2_1.py", line 45, in <module>
message.save_message()
File "C:\Python39-32\Lib\runpy.py", line 87, in _run_code
exec(code, run_globals)
File "C:\Python39-32\Lib\runpy.py", line 97, in _run_module_code
_run_code(code, mod_globals, init_globals,
File "C:\Python39-32\Lib\runpy.py", line 268, in run_path
return _run_module_code(code, init_globals, run_name,
File "C:\Python39-32\Lib\runpy.py", line 87, in _run_code
exec(code, run_globals)
File "C:\Python39-32\Lib\runpy.py", line 197, in _run_module_as_main (Current frame)
return _run_code(code, main_globals, None,
If anyone has any knowledge of why this might be or any follow up questions in order to help understand the problem more clearly, please let me know.
This is most probably an issue caused by improper API permissions on the registered app on the Azure Portal. Ensure that the app you have registered has 'Mail.ReadWrite' permission enabled since 'mark_as_read' is essentially a Write activity. See below:
Azure App Permissions
I had the same issue and this solved it for me.