Browse Source

Merge pull request #525 from inkhey/fix/mail_fetcher_dont_rely_on_seen/unseen_flag

Bastien Sevajol 7 years ago
parent
commit
8723863dc2
No account linked to committer's email
1 changed files with 30 additions and 15 deletions
  1. 30 15
      tracim/tracim/lib/email_fetcher.py

+ 30 - 15
tracim/tracim/lib/email_fetcher.py View File

@@ -26,8 +26,8 @@ TRACIM_SPECIAL_KEY_HEADER = 'X-Tracim-Key'
26 26
 CONTENT_TYPE_TEXT_PLAIN = 'text/plain'
27 27
 CONTENT_TYPE_TEXT_HTML = 'text/html'
28 28
 
29
-IMAP_SEEN_FLAG = imapclient.SEEN
30 29
 IMAP_CHECKED_FLAG = imapclient.FLAGGED
30
+IMAP_SEEN_FLAG = imapclient.SEEN
31 31
 
32 32
 MAIL_FETCHER_FILELOCK_TIMEOUT = 10
33 33
 MAIL_FETCHER_CONNECTION_TIMEOUT = 60*3
@@ -152,6 +152,10 @@ class DecodedMail(object):
152 152
         return None
153 153
 
154 154
 
155
+class BadIMAPFetchResponse(Exception):
156
+    pass
157
+
158
+
155 159
 class MailFetcher(object):
156 160
     def __init__(
157 161
         self,
@@ -291,6 +295,11 @@ class MailFetcher(object):
291 295
             # TODO - G.M - 10-01-2017 - Support imapclient exceptions
292 296
             # when Imapclient stable will be 2.0+
293 297
 
298
+            except BadIMAPFetchResponse as e:
299
+                log = 'Imap Fetch command return bad response.' \
300
+                      'Is someone else connected to the mailbox ?: ' \
301
+                      '{}'
302
+                logger.error(self, log.format(e.__str__()))
294 303
             # Others
295 304
             except Exception as e:
296 305
                 log = 'Mail Fetcher error {}'
@@ -342,13 +351,9 @@ class MailFetcher(object):
342 351
         """
343 352
         messages = []
344 353
 
345
-        logger.debug(self, 'Fetch unseen messages')
346
-        uids = imapc.search(['UNSEEN'])
347
-        logger.debug(self, 'Found {} unseen mails'.format(
348
-            len(uids),
349
-        ))
350
-        imapc.add_flags(uids, IMAP_SEEN_FLAG)
351
-        logger.debug(self, 'Temporary Flag {} mails as seen'.format(
354
+        logger.debug(self, 'Fetch unflagged messages')
355
+        uids = imapc.search(['UNFLAGGED'])
356
+        logger.debug(self, 'Found {} unflagged mails'.format(
352 357
             len(uids),
353 358
         ))
354 359
         for msgid, data in imapc.fetch(uids, ['BODY.PEEK[]']).items():
@@ -359,9 +364,22 @@ class MailFetcher(object):
359 364
             logger.debug(self, 'Fetch mail "{}"'.format(
360 365
                 msgid,
361 366
             ))
362
-            msg = message_from_bytes(data[b'BODY[]'])
367
+
368
+            try:
369
+                msg = message_from_bytes(data[b'BODY[]'])
370
+            except KeyError as e:
371
+                # INFO - G.M - 12-01-2018 - Fetch may return events response
372
+                # In some specific case, fetch command may return events
373
+                # response unrelated to fetch request.
374
+                # This should happen only when someone-else use the mailbox
375
+                # at the same time of the fetcher.
376
+                # see https://github.com/mjs/imapclient/issues/334
377
+                except_msg = 'fetch response : {}'.format(str(data))
378
+                raise BadIMAPFetchResponse(except_msg) from e
379
+
363 380
             msg_container = MessageContainer(msg, msgid)
364 381
             messages.append(msg_container)
382
+
365 383
         return messages
366 384
 
367 385
     def _notify_tracim(
@@ -383,7 +401,7 @@ class MailFetcher(object):
383 401
         #  if no from address for example) and catch it here
384 402
         while mails:
385 403
             mail = mails.pop()
386
-            body =  mail.get_body(
404
+            body = mail.get_body(
387 405
                 use_html_parsing=self.use_html_parsing,
388 406
                 use_txt_parsing=self.use_txt_parsing,
389 407
             )
@@ -421,17 +439,14 @@ class MailFetcher(object):
421 439
                         str(r.status_code),
422 440
                         details,
423 441
                     ))
424
-                # Flag all correctly checked mail, unseen the others
442
+                # Flag all correctly checked mail
425 443
                 if r.status_code in [200, 204, 400]:
426 444
                     imapc.add_flags((mail.uid,), IMAP_CHECKED_FLAG)
427
-                else:
428
-                    imapc.remove_flags((mail.uid,), IMAP_SEEN_FLAG)
445
+                    imapc.add_flags((mail.uid,), IMAP_SEEN_FLAG)
429 446
             # TODO - G.M - Verify exception correctly works
430 447
             except requests.exceptions.Timeout as e:
431 448
                 log = 'Timeout error to transmit fetched mail to tracim : {}'
432 449
                 logger.error(self, log.format(str(e)))
433
-                imapc.remove_flags((mail.uid,), IMAP_SEEN_FLAG)
434 450
             except requests.exceptions.RequestException as e:
435 451
                 log = 'Fail to transmit fetched mail to tracim : {}'
436 452
                 logger.error(self, log.format(str(e)))
437
-                imapc.remove_flags((mail.uid,), IMAP_SEEN_FLAG)