I'm trying to run a python script to download emails from an Outlook inbox. However, every single time on the 100th email, the connection is terminated and I get the following error:

> Account [email protected]: Exception in _get_elements: Traceback (most recent call last):
> File "C:\Program Files\Python38\lib\site-packages\urllib3\connectionpool.py", line 665, in urlopen
> httplib_response = self._make_request(
> File "C:\Program Files\Python38\lib\site-packages\urllib3\connectionpool.py", line 421, in _make_request
> six.raise_from(e, None)
> File "<string>", line 3, in raise_from
> File "C:\Program Files\Python38\lib\site-packages\urllib3\connectionpool.py", line 416, in _make_request
> httplib_response = conn.getresponse()
> File "C:\Program Files\Python38\lib\http\client.py", line 1322, in getresponse
> response.begin()
> File "C:\Program Files\Python38\lib\http\client.py", line 303, in begin
> version, status, reason = self._read_status()
> File "C:\Program Files\Python38\lib\http\client.py", line 264, in _read_status
> line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
> File "C:\Program Files\Python38\lib\socket.py", line 669, in readinto
> return self._sock.recv_into(b)
> File "C:\Program Files\Python38\lib\ssl.py", line 1241, in recv_into
> return self.read(nbytes, buffer)
> File "C:\Program Files\Python38\lib\ssl.py", line 1099, in read
> return self._sslobj.read(len, buffer)
> ConnectionResetError: [WinError 10054] An existing connection was forcibly closed by the remote host
> 
> During handling of the above exception, another exception occurred:
> 
> Traceback (most recent call last):
> File "C:\Program Files\Python38\lib\site-packages\requests\adapters.py", line 439, in send
> resp = conn.urlopen(
> File "C:\Program Files\Python38\lib\site-packages\urllib3\connectionpool.py", line 719, in urlopen
> retries = retries.increment(
> File "C:\Program Files\Python38\lib\site-packages\urllib3\util\retry.py", line 400, in increment
> raise six.reraise(type(error), error, _stacktrace)
> File "C:\Program Files\Python38\lib\site-packages\urllib3\packages\six.py", line 734, in reraise
> raise value.with_traceback(tb)
> File "C:\Program Files\Python38\lib\site-packages\urllib3\connectionpool.py", line 665, in urlopen
> httplib_response = self._make_request(
> File "C:\Program Files\Python38\lib\site-packages\urllib3\connectionpool.py", line 421, in _make_request
> six.raise_from(e, None)
> File "<string>", line 3, in raise_from
> File "C:\Program Files\Python38\lib\site-packages\urllib3\connectionpool.py", line 416, in _make_request
> httplib_response = conn.getresponse()
> File "C:\Program Files\Python38\lib\http\client.py", line 1322, in getresponse
> response.begin()
> File "C:\Program Files\Python38\lib\http\client.py", line 303, in begin
> version, status, reason = self._read_status()
> File "C:\Program Files\Python38\lib\http\client.py", line 264, in _read_status
> line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
> File "C:\Program Files\Python38\lib\socket.py", line 669, in readinto
> return self._sock.recv_into(b)
> File "C:\Program Files\Python38\lib\ssl.py", line 1241, in recv_into
> return self.read(nbytes, buffer)
> File "C:\Program Files\Python38\lib\ssl.py", line 1099, in read
> return self._sslobj.read(len, buffer)
> urllib3.exceptions.ProtocolError: ('Connection aborted.', ConnectionResetError(10054, 'An existing connection was forcibly closed by the remote host', None, 10054, None))
> 
> During handling of the above exception, another exception occurred:
> 
> Traceback (most recent call last):
> File "C:\Program Files\Python38\lib\site-packages\exchangelib\services\common.py", line 330, in _get_elements
> yield from self._response_generator(payload=payload)
> File "C:\Program Files\Python38\lib\site-packages\exchangelib\services\common.py", line 292, in _response_generator
> response = self._get_response_xml(payload=payload)
> File "C:\Program Files\Python38\lib\site-packages\exchangelib\services\common.py", line 416, in _get_response_xml
> r = self._get_response(payload=payload, api_version=api_version)
> File "C:\Program Files\Python38\lib\site-packages\exchangelib\services\common.py", line 370, in _get_response
> r, session = post_ratelimited(
> File "C:\Program Files\Python38\lib\site-packages\exchangelib\util.py", line 917, in post_ratelimited
> protocol.retry_policy.raise_response_errors(r)  # Always raises an exception
> File "C:\Program Files\Python38\lib\site-packages\exchangelib\protocol.py", line 700, in raise_response_errors
> raise response.headers["TimeoutException"]
> File "C:\Program Files\Python38\lib\site-packages\exchangelib\util.py", line 843, in post_ratelimited
> r = session.post(
> File "C:\Program Files\Python38\lib\site-packages\requests\sessions.py", line 581, in post
> return self.request('POST', url, data=data, json=json, **kwargs)
> File "C:\Program Files\Python38\lib\site-packages\requests_oauthlib\oauth2_session.py", line 515, in request
> return super(OAuth2Session, self).request(
> File "C:\Program Files\Python38\lib\site-packages\requests\sessions.py", line 533, in request
> resp = self.send(prep, **send_kwargs)
> File "C:\Program Files\Python38\lib\site-packages\requests\sessions.py", line 646, in send
> r = adapter.send(request, **kwargs)
> File "C:\Program Files\Python38\lib\site-packages\requests\adapters.py", line 498, in send
> raise ConnectionError(err, request=request)
> requests.exceptions.ConnectionError: ('Connection aborted.', ConnectionResetError(10054, 'An existing connection was forcibly closed by the remote host', None, 10054, None))

Code block causing the error:

    for aNum, item in enumerate(unprocessed_emails.filter(subject__contains='Notification').order_by('-datetime_received')):

        emailBody = item.body
        emailBody = emailBody.split('has invited you to view:<br><a href="')
        emailSubject = item.subject
        link = ((emailBody[1]).split('" originalsrc="'))[0]
        #Opens link  which auto-downloads file
        #webbrowser.open_new(link)    
        r = requests.get(link, allow_redirects=True) 
        try:
            sleep(2)
            eMessage = f"{aNum} of {emailCount}: Processing email with subject:  {emailSubject}"
            myLogger.info(msg=eMessage)
            filename = getFilename_fromCd(r.headers.get('content-disposition')).replace(":","_")
        except Exception as e:
            exceptionContent = getFilename_fromCd(r.headers.get('content-disposition'))
            eMessage = str('Connection to Office365 Exchange API Failed\n' + 'Error Message:  ' + str(e) + '\nContent that caused exception:\n{exceptionContent}\nContinuing...')
            myLogger.critical(msg=eMessage)
            supportMessage = f""
            try:
                sendEmailToSupport(supportMessage)
            except Exception as e2:
                eMessage2 = str('Attempt to send email to support failed. Error Message:  ' + str(e))
                myLogger.critical(msg=eMessage2)
                continue
            continue
        print(filename)

        if "event" in emailSubject.lower():
            with open(os.path.join(SourcePath, filename), 'wb') as aFile:
                aFile.write(r.content)
        elif "alarm" in emailSubject.lower():
            with open(os.path.join(ASourcePath, filename), 'wb') as aFile:
                aFile.write(r.content)
        print(reportCounter)
        reportCounter += 1`

No idea what's causing the issue. The connection timeout occurs only on the 100th email being downloaded, I'm guessing that it's triggering some download limit, but I can't seem to find anything online.

1

There are 1 best solutions below

0
Erik Cederstrand On

Your example code is missing the part where you define the account and connection settings, but the general solution to have your script survive hitting connection errors is to set a retry policy. See https://ecederstrand.github.io/exchangelib/#fault-tolerance

Example:

credentials = Credentials(...)
config = Configuration(
  retry_policy=FaultTolerance(max_wait=3600), credentials=credentials
)
account = Account(primary_smtp_address='[email protected]', config=config)