|
@@ -22,9 +22,16 @@ CONTENT_TYPE_TEXT_PLAIN = 'text/plain'
|
22
|
22
|
CONTENT_TYPE_TEXT_HTML = 'text/html'
|
23
|
23
|
|
24
|
24
|
|
|
25
|
+class MessageContainer(object):
|
|
26
|
+ def __init__(self, message: Message, uid: int) -> None:
|
|
27
|
+ self.message = message
|
|
28
|
+ self.uid = uid
|
|
29
|
+
|
|
30
|
+
|
25
|
31
|
class DecodedMail(object):
|
26
|
|
- def __init__(self, message: Message) -> None:
|
|
32
|
+ def __init__(self, message: Message, uid: int=None) -> None:
|
27
|
33
|
self._message = message
|
|
34
|
+ self.uid = uid
|
28
|
35
|
|
29
|
36
|
def _decode_header(self, header_title: str) -> typing.Optional[str]:
|
30
|
37
|
# FIXME : Handle exception
|
|
@@ -186,10 +193,8 @@ class MailFetcher(object):
|
186
|
193
|
try:
|
187
|
194
|
self._connect()
|
188
|
195
|
messages = self._fetch()
|
189
|
|
- # TODO - G.M - 2017-11-22 retry sending unsended mail
|
190
|
|
- # These mails are return by _notify_tracim, flag them with "unseen" # nopep8
|
191
|
|
- # or store them until new _notify_tracim call
|
192
|
|
- cleaned_mails = [DecodedMail(msg) for msg in messages]
|
|
196
|
+ cleaned_mails = [DecodedMail(m.message, m.uid)
|
|
197
|
+ for m in messages]
|
193
|
198
|
self._notify_tracim(cleaned_mails)
|
194
|
199
|
self._disconnect()
|
195
|
200
|
except Exception as e:
|
|
@@ -237,7 +242,7 @@ class MailFetcher(object):
|
237
|
242
|
self._connection.logout()
|
238
|
243
|
self._connection = None
|
239
|
244
|
|
240
|
|
- def _fetch(self) -> typing.List[Message]:
|
|
245
|
+ def _fetch(self) -> typing.List[MessageContainer]:
|
241
|
246
|
"""
|
242
|
247
|
Get news message from mailbox
|
243
|
248
|
:return: list of new mails
|
|
@@ -266,21 +271,22 @@ class MailFetcher(object):
|
266
|
271
|
logger.debug(self, 'Found {} unseen mails'.format(
|
267
|
272
|
len(data[0].split()),
|
268
|
273
|
))
|
269
|
|
- for num in data[0].split():
|
270
|
|
- # INFO - G.M - 2017-11-23 - Fetch (RFC288) to retrieve all
|
271
|
|
- # complete mails see example : https://docs.python.org/fr/3.5/library/imaplib.html#imap4-example . # nopep8
|
272
|
|
- # Be careful, This method remove also mails from Unseen
|
273
|
|
- # mails
|
|
274
|
+ for uid in data[0].split():
|
|
275
|
+ # INFO - G.M - 2017-12-08 - Fetch BODY.PEEK[]
|
|
276
|
+ # Retrieve all mail(body and header) but don't set mail
|
|
277
|
+ # as seen because of PEEK
|
|
278
|
+ # see rfc3501
|
274
|
279
|
logger.debug(self, 'Fetch mail "{}"'.format(
|
275
|
|
- num,
|
|
280
|
+ uid,
|
276
|
281
|
))
|
277
|
|
- rv, data = self._connection.fetch(num, '(RFC822)')
|
|
282
|
+ rv, data = self._connection.fetch(uid, 'BODY.PEEK[]')
|
278
|
283
|
logger.debug(self, 'Response status {}'.format(
|
279
|
284
|
rv,
|
280
|
285
|
))
|
281
|
286
|
if rv == 'OK':
|
282
|
287
|
msg = message_from_bytes(data[0][1])
|
283
|
|
- messages.append(msg)
|
|
288
|
+ msg_container = MessageContainer(msg, uid)
|
|
289
|
+ messages.append(msg_container)
|
284
|
290
|
else:
|
285
|
291
|
log = 'IMAP : Unable to get mail : {}'
|
286
|
292
|
logger.error(self, log.format(str(rv)))
|
|
@@ -335,6 +341,8 @@ class MailFetcher(object):
|
335
|
341
|
str(r.status_code),
|
336
|
342
|
details,
|
337
|
343
|
))
|
|
344
|
+ else:
|
|
345
|
+ self._set_flag(mail.uid)
|
338
|
346
|
# TODO - G.M - Verify exception correctly works
|
339
|
347
|
except requests.exceptions.Timeout as e:
|
340
|
348
|
log = 'Timeout error to transmit fetched mail to tracim : {}'
|
|
@@ -345,3 +353,17 @@ class MailFetcher(object):
|
345
|
353
|
logger.error(self, log.format(str(e)))
|
346
|
354
|
|
347
|
355
|
return unsended_mails
|
|
356
|
+
|
|
357
|
+ def _set_flag(self, uid):
|
|
358
|
+ assert uid is not None
|
|
359
|
+ rv, data = self._connection.store(
|
|
360
|
+ uid,
|
|
361
|
+ '+FLAGS',
|
|
362
|
+ '\\Seen'
|
|
363
|
+ )
|
|
364
|
+ if rv == 'OK':
|
|
365
|
+ log = 'Message {} set as seen.'.format(uid)
|
|
366
|
+ logger.debug(self, log)
|
|
367
|
+ else:
|
|
368
|
+ log = 'Can not set Message {} as seen : {}'.format(uid, rv)
|
|
369
|
+ logger.error(self, log)
|