From 01984e2ba89bf3a6123877063fd6e6bba181c9a4 Mon Sep 17 00:00:00 2001 From: Pietro Mingo Date: Tue, 26 Jul 2022 21:32:10 +0200 Subject: [PATCH] Update models.py, __init__.py, and office365.py --- django_mailbox/models.py | 5 +- django_mailbox/transports/__init__.py | 1 + django_mailbox/transports/office365.py | 129 +++++++++++++++++++++++++ 3 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 django_mailbox/transports/office365.py diff --git a/django_mailbox/models.py b/django_mailbox/models.py index 0f0ac9d..9ef29ac 100644 --- a/django_mailbox/models.py +++ b/django_mailbox/models.py @@ -31,7 +31,7 @@ from django_mailbox import utils from django_mailbox.signals import message_received from django_mailbox.transports import Pop3Transport, ImapTransport, \ MaildirTransport, MboxTransport, BabylTransport, MHTransport, \ - MMDFTransport, GmailImapTransport + MMDFTransport, GmailImapTransport, Office365Transport logger = logging.getLogger(__name__) @@ -223,6 +223,9 @@ class Mailbox(models.Model): ssl=self.use_ssl ) conn.connect(self.username, self.password) + elif self.type == 'office365': + conn = Office365Transport(self.location) + conn.connect(self.username, self.password) elif self.type == 'maildir': conn = MaildirTransport(self.location) elif self.type == 'mbox': diff --git a/django_mailbox/transports/__init__.py b/django_mailbox/transports/__init__.py index 7aeef95..9f733e3 100644 --- a/django_mailbox/transports/__init__.py +++ b/django_mailbox/transports/__init__.py @@ -8,3 +8,4 @@ from django_mailbox.transports.babyl import BabylTransport from django_mailbox.transports.mh import MHTransport from django_mailbox.transports.mmdf import MMDFTransport from django_mailbox.transports.gmail import GmailImapTransport +from django_mailbox.transports.office365 import Office365Transport diff --git a/django_mailbox/transports/office365.py b/django_mailbox/transports/office365.py new file mode 100644 index 0000000..8ce5554 --- /dev/null +++ b/django_mailbox/transports/office365.py @@ -0,0 +1,129 @@ +import O365 +import logging + +from django.conf import settings + +from .base import EmailTransport, MessageParseError + +logger = logging.getLogger(__name__) + + +class Office365Transport(EmailTransport): + def __init__( + self, hostname, port=None, ssl=False, tls=False, + archive='', folder=None, + ): + self.max_message_size = getattr( + settings, + 'DJANGO_MAILBOX_MAX_MESSAGE_SIZE', + False + ) + self.integration_testing_subject = getattr( + settings, + 'DJANGO_MAILBOX_INTEGRATION_TESTING_SUBJECT', + None + ) + # self.hostname = hostname + # self.port = port + # self.archive = archive + # self.folder = folder + # self.tls = tls + # if ssl: + # # self.transport = imaplib.IMAP4_SSL + # if not self.port: + # self.port = 993 + # else: + # self.transport = imaplib.IMAP4 + # if not self.port: + # self.port = 143 + + def connect(self, username, password): + # self.server = self.transport(self.hostname, self.port) + # if self.tls: + # self.server.starttls() + # typ, msg = self.server.login(username, password) + # + # if self.folder: + # self.server.select(self.folder) + # else: + # self.server.select() + + def _get_all_message_ids(self): + # # Fetch all the message uids + # response, message_ids = self.server.uid('search', None, 'ALL') + # message_id_string = message_ids[0].strip() + # # Usually `message_id_string` will be a list of space-separated + # # ids; we must make sure that it isn't an empty string before + # # splitting into individual UIDs. + # if message_id_string: + # return message_id_string.decode().split(' ') + # return [] + + def _get_small_message_ids(self, message_ids): + # Using existing message uids, get the sizes and + # return only those that are under the size + # limit + safe_message_ids = [] + + status, data = self.server.uid( + 'fetch', + ','.join(message_ids), + '(RFC822.SIZE)' + ) + + for each_msg in data: + each_msg = each_msg.decode() + try: + uid = each_msg.split(' ')[2] + size = each_msg.split(' ')[4].rstrip(')') + if int(size) <= int(self.max_message_size): + safe_message_ids.append(uid) + except ValueError as e: + logger.warning( + "ValueError: {} working on {}".format(e, each_msg[0]) + ) + pass + return safe_message_ids + + def get_message(self, condition=None): + message_ids = self._get_all_message_ids() + + 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 uid in message_ids: + try: + typ, msg_contents = self.server.uid('fetch', uid, '(RFC822)') + if not msg_contents: + continue + try: + message = self.get_email_from_bytes(msg_contents[0][1]) + except TypeError: + # This happens if another thread/process deletes the + # message between our generating the ID list and our + # processing it here. + continue + + if condition and not condition(message): + continue + + yield message + except MessageParseError: + continue + + if self.archive: + self.server.uid('copy', uid, self.archive) + + self.server.uid('store', uid, "+FLAGS", "(\\Deleted)") + self.server.expunge() + return