diff --git a/django_mailbox/models.py b/django_mailbox/models.py index d98ba1fd..4c76dc55 100644 --- a/django_mailbox/models.py +++ b/django_mailbox/models.py @@ -300,7 +300,7 @@ def _get_dehydrated_message(self, msg, record): new = EmailMessage() if ( msg.is_multipart() - and not 'attachment' in msg.get('Content-Disposition', '') + and 'attachment' not in msg.get('Content-Disposition', '') ): for header, value in msg.items(): new[header] = value @@ -647,14 +647,24 @@ def to_addresses(self): return addresses def reply(self, message): - """Sends a message as a reply to this message instance. + """Sends an EmailMessage as a reply to this message instance:: + + from django.core.mail import EmailMessage + + message.reply( + EmailMessage(subject="pong", body="pongpong") + ) Although Django's e-mail processing will set both Message-ID and Date upon generating the e-mail message, we will not be able to retrieve that information through normal channels, so we must pre-set it. - """ + from django.core.mail import EmailMessage as DjangoEmailMessage + + if not isinstance(message, DjangoEmailMessage): + raise ValueError('Message must be an instance of django.core.mail.EmailMessage') + if not message.from_email: if self.mailbox.from_email: message.from_email = self.mailbox.from_email @@ -888,7 +898,6 @@ def __str__(self): return f'{self.get_filename()}: {self.document.url}' return self.get_filename() - class Meta: verbose_name = _('Message attachment') verbose_name_plural = _('Message attachments') diff --git a/django_mailbox/tests/test_process_email.py b/django_mailbox/tests/test_process_email.py index d3316e89..50d43ff6 100644 --- a/django_mailbox/tests/test_process_email.py +++ b/django_mailbox/tests/test_process_email.py @@ -345,6 +345,9 @@ def test_message_reply(self): ) msg = self.mailbox.record_outgoing_message(email_object.message()) + with self.assertRaises(ValueError): + msg.reply(Message(subject="ping", body="pong")) + self.assertTrue(msg.outgoing) actual_from = 'username@example.com' @@ -439,7 +442,7 @@ def test_message_compressed(self): msg = self.mailbox.process_incoming_message(message) - actual_email_object = msg.get_email_object() + _actual_email_object = msg.get_email_object() self.assertTrue(msg.eml.name.endswith('.eml.gz')) diff --git a/django_mailbox/transports/base.py b/django_mailbox/transports/base.py index 57679f8a..51c6b54e 100644 --- a/django_mailbox/transports/base.py +++ b/django_mailbox/transports/base.py @@ -11,4 +11,4 @@ def get_email_from_bytes(self, contents): return message def close(self): - pass \ No newline at end of file + pass diff --git a/django_mailbox/transports/imap.py b/django_mailbox/transports/imap.py index 5b0d2dc8..fb67a8dd 100644 --- a/django_mailbox/transports/imap.py +++ b/django_mailbox/transports/imap.py @@ -53,7 +53,7 @@ def close(self): try: self.server.close() self.server.logout() - except (imaplib.IMAP4.error, OSError) as e: + except (imaplib.IMAP4.error, OSError) as e: logger.warning(f'Failed to close IMAP connection, ignoring: {e}') pass diff --git a/docs/topics/mailbox_types.rst b/docs/topics/mailbox_types.rst index 6fabf768..349986ef 100644 --- a/docs/topics/mailbox_types.rst +++ b/docs/topics/mailbox_types.rst @@ -7,20 +7,20 @@ POP3 and IMAP as well as local file-based mailboxes. .. table:: 'Protocol' Options - ============ ================ ==================================================================================================================================================================== - Mailbox Type 'Protocol':// Notes - ============ ================ ==================================================================================================================================================================== - POP3 ``pop3://`` Can also specify SSL with ``pop3+ssl://`` - IMAP ``imap://`` Can also specify SSL with ``imap+ssl://`` or STARTTLS with ``imap+tls``; additional configuration is also possible: see :ref:`pop3-and-imap-mailboxes` for details. - Gmail IMAP ``gmail+ssl://`` Uses OAuth authentication for Gmail's IMAP transport. See :ref:`gmail-oauth` for details. - Office365 API``office365://`` Uses OAuth authentication for Office365 API transport. See :ref:`office365-oauth` for details. - Maildir ``maildir://`` - Mbox ``mbox://`` - Babyl ``babyl://`` - MH ``mh://`` - MMDF ``mmdf://`` - Piped Mail *empty* See :ref:`receiving-mail-from-exim4-or-postfix` - ============ ================ ==================================================================================================================================================================== + ================ ================ ==================================================================================================================================================================== + Mailbox Type 'Protocol':// Notes + ================ ================ ==================================================================================================================================================================== + POP3 ``pop3://`` Can also specify SSL with ``pop3+ssl://`` + IMAP ``imap://`` Can also specify SSL with ``imap+ssl://`` or STARTTLS with ``imap+tls``; additional configuration is also possible: see :ref:`pop3-and-imap-mailboxes` for details. + Gmail IMAP ``gmail+ssl://`` Uses OAuth authentication for Gmail's IMAP transport. See :ref:`gmail-oauth` for details. + Office365 API ``office365://`` Uses OAuth authentication for Office365 API transport. See :ref:`office365-oauth` for details. + Maildir ``maildir://`` *empty* + Mbox ``mbox://`` *empty* + Babyl ``babyl://`` *empty* + MH ``mh://`` *empty* + MMDF ``mmdf://`` *empty* + Piped Mail *empty* See :ref:`receiving-mail-from-exim4-or-postfix` + ================ ================ ==================================================================================================================================================================== .. warning:: @@ -117,6 +117,7 @@ Build your URI accordingly:: .. _office365-oauth: + Office 365 API -------------------------------------