From 21b0be1b36ada3af96b81ab75a36ad759796bc00 Mon Sep 17 00:00:00 2001 From: Christopher Broderick Date: Wed, 2 Apr 2025 10:15:39 +0100 Subject: [PATCH] Tests for emails with attachment and no content part or attachment and empty content part. --- helpdesk/email.py | 10 ++++++-- helpdesk/tests/test_get_email.py | 39 ++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/helpdesk/email.py b/helpdesk/email.py index 046bc72f..a85e35e0 100644 --- a/helpdesk/email.py +++ b/helpdesk/email.py @@ -850,6 +850,9 @@ def extract_email_message_content( replies must be extracted """ message_part: MIMEPart = part.get_body() + # handle the case where there is no content, just an attachment + if not message_part: + return None, None parent_part: MIMEPart = part content_type = message_part.get_content_type() # Handle the possibility of a related part formatted email @@ -902,7 +905,9 @@ def extract_email_message_content( # Is either text/plain or some random content-type so just decode the part content and store as is mime_content = mime_content_to_string(message_part) # We should now have the mime content - filtered_body = parse_email_content(mime_content, include_chained_msgs) + filtered_body = ( + parse_email_content(mime_content, include_chained_msgs) if mime_content else "" + ) if not filtered_body or "" == filtered_body.strip(): # A unit test that has a different HTML content to plain text which seems an invalid case as email # tools should retain the HTML to be consistent with the plain text but manage this as a special case @@ -1088,7 +1093,8 @@ def extract_email_metadata( counter, content_parts_excluded = extract_attachments( message_obj, files, logger ) - if not content_parts_excluded: + # Check if there is expected to be a content part + if not content_parts_excluded and (filtered_body or full_body): # Unexpected situation and may mean there is a hole in the email processing logic logger.warning( "Failed to exclude email content when parsing all MIME parts in the multipart.\ diff --git a/helpdesk/tests/test_get_email.py b/helpdesk/tests/test_get_email.py index 7d225f5b..cef14bd8 100644 --- a/helpdesk/tests/test_get_email.py +++ b/helpdesk/tests/test_get_email.py @@ -514,6 +514,45 @@ class GetEmailCommonTests(TestCase): ) self.assertIsNone(ticket, f"Ticket was created when it should not be: {ticket}") + def test_with_attachment_but_no_body_part(self): + """ + Test an email that has no body content but does have an attachment + """ + message, _, _ = utils.generate_multipart_email( + type_list=["image"], + ) + # Now send the part to the email workflow + extract_email_metadata(message.as_string(), self.queue_public, self.logger) + self.assertEqual(len(mail.outbox), 1) # @UndefinedVariable + ticket = Ticket.objects.get() + followup = ticket.followup_set.get() + # Check attachment is stored as attached file + email_attachment_found = followup.followupattachment_set.exists() + self.assertTrue( + email_attachment_found, + "Email attachment file not found in ticket attachment for empty body.", + ) + + def test_with_attachment_but_empty_body(self): + """ + Test an email that has no body content but does have an attachment + """ + message, _, _ = utils.generate_multipart_email( + type_list=["plain", "image"], + body="", + ) + # Now send the part to the email workflow + extract_email_metadata(message.as_string(), self.queue_public, self.logger) + self.assertEqual(len(mail.outbox), 1) # @UndefinedVariable + ticket = Ticket.objects.get() + followup = ticket.followup_set.get() + # Check attachment is stored as attached file + email_attachment_found = followup.followupattachment_set.exists() + self.assertTrue( + email_attachment_found, + "Email attachment file not found in ticket attachment for empty body.", + ) + class EmailTaskTests(TestCase): def setUp(self):