|
@@ -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)
|