python-o365 icon indicating copy to clipboard operation
python-o365 copied to clipboard

Transient Error

Open DaniEzzeddine opened this issue 4 years ago • 3 comments

Sending email with attachment inside 1 out of 3 times will result in Transient Error and email wont be send. Here is the full error trace:

[2021-08-06 19:16:49,244: ERROR/ForkPoolWorker-2] Task api.outlook_sender.send_email[9e07c7a4-3a0a-4634-bcfe-d33ec91fd92c] raised unexpected: HTTPError('403 Client Error: Forbidden for url: https://graph.microsoft.com/v1.0/me/sendMail | Error Message: Cannot send this mail due to a transient error. Please try again later (0x00004000)., WASCL UserAction verdict is not None. Actual verdict is TransientError.')
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/dist-packages/celery/app/trace.py", line 385, in trace_task
    R = retval = fun(*args, **kwargs)
  File "/usr/local/lib/python3.8/dist-packages/celery/app/trace.py", line 648, in __protected_call__
    return self.run(*args, **kwargs)
  File "/usr/local/lib/python3.8/dist-packages/sentry_sdk/integrations/celery.py", line 186, in _inner
    reraise(*exc_info)
  File "/usr/local/lib/python3.8/dist-packages/sentry_sdk/_compat.py", line 55, in reraise
    raise value
  File "/usr/local/lib/python3.8/dist-packages/sentry_sdk/integrations/celery.py", line 181, in _inner
    return f(*args, **kwargs)
  File "/app/backend/stylelab/api/outlook_sender.py", line 170, in send_email
    result = send_message(profile, msg)
  File "/app/backend/stylelab/api/outlook_sender.py", line 69, in send_message
    result = msg.send()
  File "/usr/local/lib/python3.8/dist-packages/O365/message.py", line 699, in send
    response = self.con.post(url, data=data)
  File "/usr/local/lib/python3.8/dist-packages/O365/connection.py", line 822, in post
    return self.oauth_request(url, 'post', data=data, **kwargs)
  File "/usr/local/lib/python3.8/dist-packages/O365/connection.py", line 800, in oauth_request
    return self._internal_request(self.session, url, method, **kwargs)
  File "/usr/local/lib/python3.8/dist-packages/O365/connection.py", line 762, in _internal_request
    raise HTTPError('{} | Error Message: {}'.format(e.args[0], error_message), response=response) from None
requests.exceptions.HTTPError: 403 Client Error: Forbidden for url: https://graph.microsoft.com/v1.0/me/sendMail | Error Message: Cannot send this mail due to a transient error. Please try again later (0x00004000)., WASCL UserAction verdict is not None. Actual verdict is TransientError.

DaniEzzeddine avatar Aug 11 '21 21:08 DaniEzzeddine

Here is the code I use to do it

def parse_attachment(dir_path, att):
    try:
        if (att == None):
            return None
        content = urllib.urlopen(att.file.url, timeout = 10).read()
        with open(os.path.join(dir_path, att.file.name), 'wb') as temp_file:
            temp_file.write(content)

        return os.path.join(dir_path, att.file.name)
    except Exception as e:
        logger.error(f'Could not upload the attachment, Error: {e}')
        return None

def remove_attachment(dir_path):
    if dir_path != None and len(dir_path) != 0 and os.path.exists(dir_path):
        shutil.rmtree(dir_path)

def send_message(profile, message):
    try:
        from api.views import CustomTokenBackend
        logger.info(f"sending outlook from {profile.email_line()}")
        token_backend = CustomTokenBackend(profile=profile)
        account = Account(credentials=settings.OUTLOOK_CREDENTIALS, scopes=SCOPES, token_backend=token_backend)
        
        msg = account.new_message()
        msg.to.add(message["to"])
        msg.subject = message["subject"]
        msg.body = message["body"]
        temp_dir_name = tempfile.mkdtemp()
        path_to_att = parse_attachment(temp_dir_name, message['attachment'])
        if path_to_att != None and len(path_to_att) != 0:
            msg.attachments.add(path_to_att)
        result = msg.send()
        remove_attachment(temp_dir_name)
        return result
    except errors.HttpError:
        return 'Error'

DaniEzzeddine avatar Aug 11 '21 21:08 DaniEzzeddine

I have no clue... I've never seen this error. The fact that is a 403 error is strange.

I've read on google that this could be caused by some special chars being used in some of the provided fields like "to addresess", subject and so.

alejcas avatar Sep 03 '21 09:09 alejcas

@janscas Yea, thats a weird error. I solved it by adding exponential backoff retry as was recommended on microsoft graph api page.

DaniEzzeddine avatar Sep 03 '21 16:09 DaniEzzeddine