diff --git a/app/app/email/headers.py b/app/app/email/headers.py index 788693b..bfbcb9a 100644 --- a/app/app/email/headers.py +++ b/app/app/email/headers.py @@ -21,6 +21,7 @@ LIST_UNSUBSCRIBE = "List-Unsubscribe" LIST_UNSUBSCRIBE_POST = "List-Unsubscribe-Post" RETURN_PATH = "Return-Path" AUTHENTICATION_RESULTS = "Authentication-Results" +SL_QUEUE_ID = "X-SL-Queue-Id" # headers used to DKIM sign in order of preference DKIM_HEADERS = [ diff --git a/app/app/handler/dmarc.py b/app/app/handler/dmarc.py index fc1a2d1..895fa70 100644 --- a/app/app/handler/dmarc.py +++ b/app/app/handler/dmarc.py @@ -30,7 +30,9 @@ def apply_dmarc_policy_for_forward_phase( ) -> Tuple[Message, Optional[str]]: spam_result = SpamdResult.extract_from_headers(msg, Phase.forward) if not DMARC_CHECK_ENABLED or not spam_result: + LOG.i("DMARC check disabled") return msg, None + LOG.i(f"Spam check result in {spam_result}") from_header = get_header_unicode(msg[headers.FROM]) @@ -150,8 +152,10 @@ def apply_dmarc_policy_for_reply_phase( ) -> Optional[str]: spam_result = SpamdResult.extract_from_headers(msg, Phase.reply) if not DMARC_CHECK_ENABLED or not spam_result: + LOG.i("DMARC check disabled") return None + LOG.i(f"Spam check result is {spam_result}") if spam_result.dmarc not in ( DmarcCheckResult.quarantine, DmarcCheckResult.reject, diff --git a/app/app/import_utils.py b/app/app/import_utils.py index 9d4460e..6cb30cc 100644 --- a/app/app/import_utils.py +++ b/app/app/import_utils.py @@ -30,7 +30,10 @@ def handle_batch_import(batch_import: BatchImport): LOG.d("Download file %s from %s", batch_import.file, file_url) r = requests.get(file_url) - lines = [line.decode("utf-8") for line in r.iter_lines()] + # Replace invisible character + lines = [ + line.decode("utf-8").replace("\ufeff", "").strip() for line in r.iter_lines() + ] import_from_csv(batch_import, user, lines) diff --git a/app/email_handler.py b/app/email_handler.py index aa2b06b..e77fcbb 100644 --- a/app/email_handler.py +++ b/app/email_handler.py @@ -875,6 +875,7 @@ def forward_email_to_mailbox( # References and In-Reply-To are used for keeping the email thread headers.REFERENCES, headers.IN_REPLY_TO, + headers.SL_QUEUE_ID, headers.LIST_UNSUBSCRIBE, headers.LIST_UNSUBSCRIBE_POST, ] + headers.MIME_HEADERS diff --git a/app/tests/test_email_handler.py b/app/tests/test_email_handler.py index 121c226..5b33c71 100644 --- a/app/tests/test_email_handler.py +++ b/app/tests/test_email_handler.py @@ -384,3 +384,30 @@ def test_break_loop_alias_as_mailbox(flask_client): msg[headers.SUBJECT] = random_string() result = email_handler.handle(envelope, msg) assert result == status.E525 + + +@mail_sender.store_emails_test_decorator +def test_preserve_headers(flask_client): + headers_to_keep = [ + headers.SUBJECT, + headers.DATE, + headers.MESSAGE_ID, + headers.REFERENCES, + headers.IN_REPLY_TO, + headers.SL_QUEUE_ID, + ] + headers.MIME_HEADERS + user = create_new_user() + alias = Alias.create_new_random(user) + envelope = Envelope() + envelope.mail_from = "somewhere@lo.cal" + envelope.rcpt_tos = [alias.email] + msg = EmailMessage() + for header in headers_to_keep: + msg[header] = header + "keep" + result = email_handler.handle(envelope, msg) + assert result == status.E200 + sent_mails = mail_sender.get_stored_emails() + assert len(sent_mails) == 1 + msg = sent_mails[0].msg + for header in headers_to_keep: + assert msg[header] == header + "keep"