From 88b35117aee79417a5e2e8c30b25e67fa54efbe8 Mon Sep 17 00:00:00 2001 From: Mike Varga Date: Fri, 14 Oct 2022 13:49:59 -0400 Subject: [PATCH 1/3] Implement read-only mail fetching --- django_mailbox/transports/generic.py | 3 ++ django_mailbox/transports/imap.py | 45 ++++++++++++++++++++++------ django_mailbox/transports/pop3.py | 3 ++ 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/django_mailbox/transports/generic.py b/django_mailbox/transports/generic.py index 5832fda..2d27fba 100644 --- a/django_mailbox/transports/generic.py +++ b/django_mailbox/transports/generic.py @@ -24,3 +24,6 @@ class GenericFileMailbox(EmailTransport): yield message repository.flush() repository.unlock() + + def get_new_message_ro(self, since=None): + raise NotImplementedError("GenericFileMailbox.get_new_message_ro not implemented!") diff --git a/django_mailbox/transports/imap.py b/django_mailbox/transports/imap.py index 2599ada..79d5b49 100644 --- a/django_mailbox/transports/imap.py +++ b/django_mailbox/transports/imap.py @@ -99,19 +99,47 @@ class ImapTransport(EmailTransport): if not message_ids: return - # Limit the uids to the small ones if we care about that - if self.max_message_size: - message_ids = self._get_small_message_ids(message_ids) - if self.archive: typ, folders = self.server.list(pattern=self.archive) if folders[0] is None: # If the archive folder does not exist, create it self.server.create(self.archive) + for message in self._iter_messages(message_ids): + yield message + + self.server.expunge() + return + + def get_new_message_ro(self, since): + """Read-only version of `get_message`. Uses a timestamp to fetch only messages + originating later than `since` parameter. + """ + + date_format = "%d-%b-%Y" + typ, [raw_msg_ids] = self.server.search(None, '(since "%s")' % (since.strftime(date_format))) + + message_ids = raw_msg_ids.decode().split() + + if not message_ids: + return + + for message in self._iter_messages(message_ids, archive=False, delete=False): + yield message + + self.server.expunge() + return + + + def _iter_messages(self, message_ids, condition=None, archive=True, delete=True): + + # Limit the uids to the small ones if we care about that + if self.max_message_size: + message_ids = self._get_small_message_ids(message_ids) + for uid in message_ids: try: - typ, msg_contents = self.server.uid('fetch', uid, '(RFC822)') + typ, msg_contents = self.server.fetch(uid, '(RFC822)') if not msg_contents: continue try: @@ -129,9 +157,8 @@ class ImapTransport(EmailTransport): except MessageParseError: continue - if self.archive: + if archive and self.archive: self.server.uid('copy', uid, self.archive) - self.server.uid('store', uid, "+FLAGS", "(\\Deleted)") - self.server.expunge() - return + if delete: + self.server.uid('store', uid, "+FLAGS", "(\\Deleted)") \ No newline at end of file diff --git a/django_mailbox/transports/pop3.py b/django_mailbox/transports/pop3.py index 6dbe995..3c861f0 100644 --- a/django_mailbox/transports/pop3.py +++ b/django_mailbox/transports/pop3.py @@ -42,3 +42,6 @@ class Pop3Transport(EmailTransport): self.server.dele(i + 1) self.server.quit() return + + def get_new_message_ro(self, since=None): + raise NotImplementedError("Pop3Transport.get_new_message_ro not implemented!") \ No newline at end of file From 9c0cac66e25a751ae0d929d0f8dc1df7540c5aff Mon Sep 17 00:00:00 2001 From: Mike Varga Date: Fri, 14 Oct 2022 13:50:40 -0400 Subject: [PATCH 2/3] Utilize read-only method in `get_new_mail` --- django_mailbox/models.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/django_mailbox/models.py b/django_mailbox/models.py index 0f0ac9d..314d0d4 100644 --- a/django_mailbox/models.py +++ b/django_mailbox/models.py @@ -17,6 +17,7 @@ import mimetypes import os.path import sys import uuid +from datetime import timedelta from tempfile import NamedTemporaryFile import django @@ -35,6 +36,8 @@ from django_mailbox.transports import Pop3Transport, ImapTransport, \ logger = logging.getLogger(__name__) +INITIAL_IMPORT_LOOKBACK_DAYS = 365 + class MailboxQuerySet(models.QuerySet): def get_new_mail(self): @@ -420,7 +423,12 @@ class Mailbox(models.Model): connection = self.get_connection() if not connection: return - for message in connection.get_message(condition): + + since = self.last_polling + if since is None: + since = now() - timedelta(days=INITIAL_IMPORT_LOOKBACK_DAYS) + + for message in connection.get_new_message_ro(since=since): msg = self.process_incoming_message(message) if not msg is None: yield msg From 4e479e8f69c0640c47f19c4d7b3d555da6ca36da Mon Sep 17 00:00:00 2001 From: Mike Varga Date: Fri, 14 Oct 2022 13:54:56 -0400 Subject: [PATCH 3/3] Function name change --- django_mailbox/models.py | 2 +- django_mailbox/transports/generic.py | 4 ++-- django_mailbox/transports/imap.py | 2 +- django_mailbox/transports/pop3.py | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/django_mailbox/models.py b/django_mailbox/models.py index 314d0d4..bfdda0a 100644 --- a/django_mailbox/models.py +++ b/django_mailbox/models.py @@ -428,7 +428,7 @@ class Mailbox(models.Model): if since is None: since = now() - timedelta(days=INITIAL_IMPORT_LOOKBACK_DAYS) - for message in connection.get_new_message_ro(since=since): + for message in connection.get_message_ro(since=since): msg = self.process_incoming_message(message) if not msg is None: yield msg diff --git a/django_mailbox/transports/generic.py b/django_mailbox/transports/generic.py index 2d27fba..a43918a 100644 --- a/django_mailbox/transports/generic.py +++ b/django_mailbox/transports/generic.py @@ -25,5 +25,5 @@ class GenericFileMailbox(EmailTransport): repository.flush() repository.unlock() - def get_new_message_ro(self, since=None): - raise NotImplementedError("GenericFileMailbox.get_new_message_ro not implemented!") + def get_message_ro(self, since=None): + raise NotImplementedError("GenericFileMailbox.get_message_ro not implemented!") diff --git a/django_mailbox/transports/imap.py b/django_mailbox/transports/imap.py index 79d5b49..fc6951b 100644 --- a/django_mailbox/transports/imap.py +++ b/django_mailbox/transports/imap.py @@ -111,7 +111,7 @@ class ImapTransport(EmailTransport): self.server.expunge() return - def get_new_message_ro(self, since): + def get_message_ro(self, since): """Read-only version of `get_message`. Uses a timestamp to fetch only messages originating later than `since` parameter. """ diff --git a/django_mailbox/transports/pop3.py b/django_mailbox/transports/pop3.py index 3c861f0..526538e 100644 --- a/django_mailbox/transports/pop3.py +++ b/django_mailbox/transports/pop3.py @@ -43,5 +43,5 @@ class Pop3Transport(EmailTransport): self.server.quit() return - def get_new_message_ro(self, since=None): - raise NotImplementedError("Pop3Transport.get_new_message_ro not implemented!") \ No newline at end of file + def get_message_ro(self, since=None): + raise NotImplementedError("Pop3Transport.get_message_ro not implemented!") \ No newline at end of file