|
@@ -25,9 +25,15 @@ CONTENT_TYPE_TEXT_HTML = 'text/html'
|
25
|
25
|
|
26
|
26
|
IMAP_SEEN_FLAG = SEEN
|
27
|
27
|
IMAP_CHECKED_FLAG = FLAGGED
|
|
28
|
+
|
28
|
29
|
MAIL_FETCHER_FILELOCK_TIMEOUT = 10
|
29
|
|
-MAIL_FETCHER_CONNECTION_TIMEOUT = 60*9
|
30
|
|
-IDLE_MODE = True
|
|
30
|
+MAIL_FETCHER_CONNECTION_TIMEOUT = 60*3
|
|
31
|
+MAIL_FETCHER_CONNECTION_MAX_LIFETIME = 60*10
|
|
32
|
+MAIL_FETCHER_IDLE_RESPONSE_TIMEOUT = 60*9 # this should be not more
|
|
33
|
+# that 29 minutes according to rfc2177.(server wait 30min by default)
|
|
34
|
+
|
|
35
|
+IDLE_MODE = False
|
|
36
|
+
|
31
|
37
|
|
32
|
38
|
class MessageContainer(object):
|
33
|
39
|
def __init__(self, message: Message, uid: int) -> None:
|
|
@@ -195,27 +201,49 @@ class MailFetcher(object):
|
195
|
201
|
def run(self) -> None:
|
196
|
202
|
logger.info(self, 'Starting MailFetcher')
|
197
|
203
|
while self._is_active:
|
|
204
|
+
|
|
205
|
+ # login/connection
|
198
|
206
|
try:
|
199
|
|
- imapc = IMAPClient(self.host, self.port, ssl=self.use_ssl)
|
|
207
|
+ imapc = IMAPClient(self.host,
|
|
208
|
+ self.port,
|
|
209
|
+ ssl=self.use_ssl,
|
|
210
|
+ timeout=MAIL_FETCHER_CONNECTION_TIMEOUT)
|
200
|
211
|
imapc.login(self.user, self.password)
|
201
|
|
- # select mailbox
|
|
212
|
+ except Exception as e:
|
|
213
|
+ log = 'Fail to connect to IMAP {}'
|
|
214
|
+ logger.error(self, log.format(e.__str__()))
|
|
215
|
+ logger.debug(self, 'sleep for {}'.format(self.delay))
|
|
216
|
+ time.sleep(self.delay)
|
|
217
|
+ continue
|
|
218
|
+
|
|
219
|
+ # fetching
|
|
220
|
+ try:
|
|
221
|
+ # select folder
|
202
|
222
|
logger.debug(self, 'Select folder {}'.format(
|
203
|
223
|
self.folder,
|
204
|
224
|
))
|
205
|
|
- deadline = time.time() + MAIL_FETCHER_CONNECTION_TIMEOUT
|
|
225
|
+ imapc.select_folder(self.folder)
|
|
226
|
+
|
|
227
|
+ # force renew connection when deadline is reached
|
|
228
|
+ deadline = time.time() + MAIL_FETCHER_CONNECTION_MAX_LIFETIME
|
206
|
229
|
while time.time() < deadline:
|
|
230
|
+ # check for new mails
|
207
|
231
|
self._check_mail(imapc)
|
208
|
232
|
|
209
|
233
|
if IDLE_MODE and imapc.has_capability('IDLE'):
|
|
234
|
+ # IDLE_mode: wait until event from server
|
210
|
235
|
logger.debug(self, 'wail for event(IDLE)')
|
211
|
236
|
imapc.idle()
|
212
|
237
|
imapc.idle_check(
|
213
|
|
- timeout=MAIL_FETCHER_CONNECTION_TIMEOUT
|
|
238
|
+ timeout=MAIL_FETCHER_IDLE_RESPONSE_TIMEOUT
|
214
|
239
|
)
|
215
|
240
|
imapc.idle_done()
|
216
|
241
|
else:
|
|
242
|
+ # normal polling mode : sleep a define duration
|
217
|
243
|
logger.debug(self, 'sleep for {}'.format(self.delay))
|
218
|
244
|
time.sleep(self.delay)
|
|
245
|
+
|
|
246
|
+ logger.debug(self,"Lifetime limit excess, Renew connection")
|
219
|
247
|
except filelock.Timeout as e:
|
220
|
248
|
log = 'Mail Fetcher Lock Timeout {}'
|
221
|
249
|
logger.warning(self, log.format(e.__str__()))
|
|
@@ -223,7 +251,20 @@ class MailFetcher(object):
|
223
|
251
|
log = 'Mail Fetcher error {}'
|
224
|
252
|
logger.error(self, log.format(e.__str__()))
|
225
|
253
|
finally:
|
226
|
|
- imapc.logout()
|
|
254
|
+ # INFO - G.M - 2018-01-09 - Connection closing
|
|
255
|
+ # Properly close connection according to
|
|
256
|
+ # https://github.com/mjs/imapclient/pull/279/commits/043e4bd0c5c775c5a08cb5f1baa93876a46732ee
|
|
257
|
+ # TODO : Use __exit__ method instead when imapclient stable will
|
|
258
|
+ # be 2.0+ .
|
|
259
|
+ logger.debug(self, 'Try logout')
|
|
260
|
+ try:
|
|
261
|
+ imapc.logout()
|
|
262
|
+ except Exception:
|
|
263
|
+ try:
|
|
264
|
+ imapc.shutdown()
|
|
265
|
+ except Exception as e:
|
|
266
|
+ log = "Can't logout, connection broken ? {}"
|
|
267
|
+ logger.error(self, log.format(e.__str__()))
|
227
|
268
|
|
228
|
269
|
def _check_mail(self, imapc: IMAPClient) -> None:
|
229
|
270
|
with self.lock.acquire(
|
|
@@ -244,7 +285,6 @@ class MailFetcher(object):
|
244
|
285
|
"""
|
245
|
286
|
messages = []
|
246
|
287
|
|
247
|
|
- imapc.select_folder(self.folder)
|
248
|
288
|
logger.debug(self, 'Fetch unseen messages')
|
249
|
289
|
uids = imapc.search(['UNSEEN'])
|
250
|
290
|
logger.debug(self, 'Found {} unseen mails'.format(
|