diff --git a/app/email_utils.py b/app/email_utils.py index c80aabc0..1904fd3b 100644 --- a/app/email_utils.py +++ b/app/email_utils.py @@ -598,22 +598,53 @@ def mailbox_already_used(email: str, user) -> bool: return False -def get_orig_message_from_bounce(msg: Message) -> Message: +def get_orig_message_from_bounce(bounce_report: Message) -> Optional[Message]: """parse the original email from Bounce""" i = 0 - for part in msg.walk(): + for part in bounce_report.walk(): i += 1 - # the original message is the 4th part - # 1st part is the root part, multipart/report - # 2nd is text/plain, Postfix log + # 1st part is the container (bounce report) + # 2nd part is the report from our own Postfix + # 3rd is report from other mailbox + # 4th is the container of the original message # ... # 7th is original message if i == 7: return part -def get_orig_message_from_hotmail_complaint(msg: Message) -> Message: +def get_mailbox_bounce_info(bounce_report: Message) -> Optional[Message]: + """ + Return the bounce info from the bounce report + An example of bounce info: + + Final-Recipient: rfc822; not-existing@gmail.com + Original-Recipient: rfc822;not-existing@gmail.com + Action: failed + Status: 5.1.1 + Remote-MTA: dns; gmail-smtp-in.l.google.com + Diagnostic-Code: smtp; + 550-5.1.1 The email account that you tried to reach does + not exist. Please try 550-5.1.1 double-checking the recipient's email + address for typos or 550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1 + https://support.google.com/mail/?p=NoSuchUser z127si6173191wmc.132 - gsmtp + + """ + i = 0 + for part in bounce_report.walk(): + i += 1 + + # 1st part is the container (bounce report) + # 2nd part is the report from our own Postfix + # 3rd is report from other mailbox + # 4th is the container of the original message + # 5th is a child of 3rd that contains more info about the bounce + if i == 5: + return part + + +def get_orig_message_from_hotmail_complaint(msg: Message) -> Optional[Message]: i = 0 for part in msg.walk(): i += 1 @@ -625,7 +656,7 @@ def get_orig_message_from_hotmail_complaint(msg: Message) -> Message: return part -def get_orig_message_from_yahoo_complaint(msg: Message) -> Message: +def get_orig_message_from_yahoo_complaint(msg: Message) -> Optional[Message]: i = 0 for part in msg.walk(): i += 1 diff --git a/local_data/email_tests/bounce.eml b/local_data/email_tests/bounce.eml new file mode 100644 index 00000000..4498aa27 --- /dev/null +++ b/local_data/email_tests/bounce.eml @@ -0,0 +1,102 @@ +Received: by mx1.sl.co (Postfix) + id F09806333D; Thu, 14 Oct 2021 09:14:44 +0000 (UTC) +Date: Thu, 14 Oct 2021 09:14:44 +0000 (UTC) +From: mailer-daemon@bounce.sl.co (Mail Delivery System) +Subject: Undelivered Mail Returned to Sender +To: bounce+5352+@sl.co +Auto-Submitted: auto-replied +MIME-Version: 1.0 +Content-Type: multipart/report; report-type=delivery-status; + boundary="8A32A6333B.1634202884/mx1.sl.co" +Content-Transfer-Encoding: 8bit +Message-Id: <20211014091444.F09806333D@mx1.sl.co> + +This is a MIME-encapsulated message. + +--8A32A6333B.1634202884/mx1.sl.co +Content-Description: Notification +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 8bit + +This is the mail system at host mx1.sl.co. + +I'm sorry to have to inform you that your message could not +be delivered to one or more recipients. It's attached below. + +For further assistance, please send mail to + +If you do so, please include this problem report. You can +delete your own text from the attached returned message. + + The mail system + +: host + gmail-smtp-in.l.google.com[142.251.5.27] said: 550-5.1.1 The email account + that you tried to reach does not exist. Please try 550-5.1.1 + double-checking the recipient's email address for typos or 550-5.1.1 + unnecessary spaces. Learn more at 550 5.1.1 + https://support.google.com/mail/?p=NoSuchUser z127si6173191wmc.132 - gsmtp + (in reply to RCPT TO command) + +--8A32A6333B.1634202884/mx1.sl.co +Content-Description: Delivery report +Content-Type: message/delivery-status + +Reporting-MTA: dns; mx1.sl.co +X-Postfix-Queue-ID: 8A32A6333B +X-Postfix-Sender: rfc822; bounce+5352+@sl.co +Arrival-Date: Thu, 14 Oct 2021 09:14:44 +0000 (UTC) + +Final-Recipient: rfc822; not-existing@gmail.com +Original-Recipient: rfc822;not-existing@gmail.com +Action: failed +Status: 5.1.1 +Remote-MTA: dns; gmail-smtp-in.l.google.com +Diagnostic-Code: smtp; + 550-5.1.1 The email account that you tried to reach does + not exist. Please try 550-5.1.1 double-checking the recipient's email + address for typos or 550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1 + https://support.google.com/mail/?p=NoSuchUser z127si6173191wmc.132 - gsmtp + +--8A32A6333B.1634202884/mx1.sl.co +Content-Description: Undelivered Message +Content-Type: message/rfc822 +Content-Transfer-Encoding: 8bit + +Return-Path: +X-SimpleLogin-Client-IP: 90.127.20.84 +Received: from 2a01cb00008c9c001a3eeffffec79eea.ipv6.abo.wanadoo.fr + (lfbn-idf1-1-2034-84.w90-127.abo.wanadoo.fr [90.127.20.84]) + (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) + (No client certificate requested) + by mx1.sl.co (Postfix) with ESMTPS id 8A32A6333B + for ; + Thu, 14 Oct 2021 09:14:44 +0000 (UTC) +Content-Type: text/plain; + charset=us-ascii +Content-Transfer-Encoding: 7bit +Mime-Version: 1.0 (Mac OS X Mail 14.0 \(3654.120.0.1.13\)) +Subject: bounce 5 +Message-Id: +X-SimpleLogin-Type: Forward +X-SimpleLogin-EmailLog-ID: 5352 +X-SimpleLogin-Envelope-From: sender@gmail.com +X-SimpleLogin-Envelope-To: heyheyalo@sl.co +date: Thu, 14 Oct 2021 09:14:44 -0000 +From: "First Last - sender at gmail.com" + +To: heyheyalo@sl.co +List-Unsubscribe: +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=sl.co; + i=@sl.co; q=dns/txt; s=dkim; t=1634202884; + h=message-id : date : subject : from : to; + bh=ktjzaMYZHA8J5baAHC3QyOmFwAAv/MvNtIz1dvmI3V0=; + b=mzf2ZDIVshKSSjw4AQnrOttgRRjzYzZ+49PaPRobt0xFH0E02a2C9Rl/qLEshLHA7amba + 8iNTzdTkp9UJquzjk3NwM9GCakmSzd9DmFsalkgeErDAKWNo2O2c7aYDHZlK/sp2vgsIcSO + 1w6sp8sVIRr2JrnFPxFOfsOSkSabeOA= + +Alo quoi + + + +--8A32A6333B.1634202884/mx1.sl.co-- diff --git a/tests/test_email_utils.py b/tests/test_email_utils.py index 66f3e9b0..bd4aac38 100644 --- a/tests/test_email_utils.py +++ b/tests/test_email_utils.py @@ -1,9 +1,10 @@ import email +import os from email.message import EmailMessage import arrow -from app.config import MAX_ALERT_24H, EMAIL_DOMAIN, BOUNCE_EMAIL +from app.config import MAX_ALERT_24H, EMAIL_DOMAIN, BOUNCE_EMAIL, ROOT_DIR from app.db import Session from app.email_utils import ( get_email_domain_part, @@ -31,6 +32,8 @@ from app.email_utils import ( should_ignore_bounce, get_header_unicode, parse_full_address, + get_orig_message_from_bounce, + get_mailbox_bounce_info, ) from app.models import User, CustomDomain, Alias, Contact, EmailLog, IgnoreBounceSender @@ -748,3 +751,21 @@ def test_should_ignore_bounce(flask_client): def test_get_header_unicode(): assert get_header_unicode("ab@cd.com") == "ab@cd.com" assert get_header_unicode("=?utf-8?B?w6nDqQ==?=@example.com") == "éé@example.com" + + +def test_get_orig_message_from_bounce(): + with open(os.path.join(ROOT_DIR, "local_data", "email_tests", "bounce.eml")) as f: + bounce_report = email.message_from_file(f) + + orig_msg = get_orig_message_from_bounce(bounce_report) + assert orig_msg["X-SimpleLogin-Type"] == "Forward" + assert orig_msg["X-SimpleLogin-Envelope-From"] == "sender@gmail.com" + + +def test_get_mailbox_bounce_info(): + with open(os.path.join(ROOT_DIR, "local_data", "email_tests", "bounce.eml")) as f: + bounce_report = email.message_from_file(f) + + orig_msg = get_mailbox_bounce_info(bounce_report) + assert orig_msg["Final-Recipient"] == "rfc822; not-existing@gmail.com" + assert orig_msg["Original-Recipient"] == "rfc822;not-existing@gmail.com"