From b53da25a41eeb51eb208addb9059f410a4eeae98 Mon Sep 17 00:00:00 2001 From: Son Nguyen Kim Date: Mon, 6 Sep 2021 19:44:18 +0200 Subject: [PATCH] handle hotmail complaint --- app/config.py | 4 ++ app/email/status.py | 2 + app/email_utils.py | 13 ++++++ email_handler.py | 43 +++++++++++++++++++ .../transactional/hotmail-complaint.html | 33 ++++++++++++++ .../hotmail-complaint.txt.jinja2 | 17 ++++++++ 6 files changed, 112 insertions(+) create mode 100644 templates/emails/transactional/hotmail-complaint.html create mode 100644 templates/emails/transactional/hotmail-complaint.txt.jinja2 diff --git a/app/config.py b/app/config.py index c49109e8..1b3c869b 100644 --- a/app/config.py +++ b/app/config.py @@ -333,6 +333,8 @@ AlERT_WRONG_MX_RECORD_CUSTOM_DOMAIN = "custom_domain_mx_record_issue" # alert when a new alias is about to be created on a disabled directory ALERT_DIRECTORY_DISABLED_ALIAS_CREATION = "alert_directory_disabled_alias_creation" +ALERT_HOTMAIL_COMPLAINT = "alert_hotmail_complaint" + # <<<<< END ALERT EMAIL >>>> # Disable onboarding emails @@ -393,3 +395,5 @@ except Exception: HIBP_API_KEYS = sl_getenv("HIBP_API_KEYS", list) or [] NEWRELIC_CONFIG_PATH = os.environ.get("NEWRELIC_CONFIG_PATH") + +POSTMASTER = os.environ.get("POSTMASTER") \ No newline at end of file diff --git a/app/email/status.py b/app/email/status.py index 7811c937..28e95ae7 100644 --- a/app/email/status.py +++ b/app/email/status.py @@ -11,6 +11,8 @@ E206 = "250 SL E206 Out of office" # if mail_from is a IgnoreBounceSender, no need to send back a bounce report E207 = "250 SL E207 No bounce report" +E208 = "250 SL E208 Hotmail complaint handled" + # 4** errors # E401 = "421 SL E401 Retry later" E402 = "421 SL E402 Encryption failed - Retry later" diff --git a/app/email_utils.py b/app/email_utils.py index 6109dd3e..8f34b121 100644 --- a/app/email_utils.py +++ b/app/email_utils.py @@ -567,6 +567,19 @@ def get_orig_message_from_bounce(msg: Message) -> Message: return part +def get_orig_message_from_outlook_complaint(msg: Message) -> Message: + """parse the original email from Bounce""" + i = 0 + for part in msg.walk(): + i += 1 + + # 1st part is the container + # 2nd part is the empty body + # 3rd is original message + if i == 3: + return part + + def get_header_from_bounce(msg: Message, header: str) -> str: """using regex to get header value from bounce message get_orig_message_from_bounce is better. This should be the last option diff --git a/email_handler.py b/email_handler.py index fed44266..08ef4d84 100644 --- a/email_handler.py +++ b/email_handler.py @@ -76,6 +76,8 @@ from app.config import ( ENABLE_SPAM_ASSASSIN, BOUNCE_PREFIX_FOR_REPLY_PHASE, NEWRELIC_CONFIG_PATH, + POSTMASTER, + ALERT_HOTMAIL_COMPLAINT, ) from app.email import status from app.email.rate_limit import rate_limited @@ -112,6 +114,7 @@ from app.email_utils import ( sanitize_header, get_queue_id, should_ignore_bounce, + get_orig_message_from_outlook_complaint, ) from app.extensions import db from app.log import LOG, set_message_id @@ -1279,6 +1282,37 @@ def handle_bounce_forward_phase(msg: Message, email_log: EmailLog): ) +def handle_hotmail_complaint(msg: Message): + """ + Handle hotmail complaint sent to postmaster + """ + orig_msg = get_orig_message_from_outlook_complaint(msg) + alias_address = orig_msg["To"] + alias = Alias.get_by(email=alias_address) + + if not alias: + LOG.d("No alias for %s", alias_address) + + user = alias.user + LOG.e("Handle hotmail complaint for %s %s", alias, user) + + send_email_with_rate_control( + user, + ALERT_HOTMAIL_COMPLAINT, + user.email, + f"Hotmail abuse report", + render( + "transactional/hotmail-complaint.txt.jinja2", + alias=alias, + ), + render( + "transactional/hotmail-complaint.html", + alias=alias, + ), + max_nb_alert=2, + ) + + def handle_bounce_reply_phase(envelope, msg: Message, email_log: EmailLog): """ Handle reply phase bounce @@ -1687,6 +1721,15 @@ def handle(envelope: Envelope) -> str: handle_transactional_bounce(envelope, rcpt_tos[0]) return status.E205 + if ( + len(rcpt_tos) == 1 + and mail_from == "staff@hotmail.com" + and rcpt_tos[0] == POSTMASTER + ): + LOG.w("Handle hotmail complaint") + handle_hotmail_complaint(msg) + return status.E208 + # Handle bounce if ( len(rcpt_tos) == 1 diff --git a/templates/emails/transactional/hotmail-complaint.html b/templates/emails/transactional/hotmail-complaint.html new file mode 100644 index 00000000..6c67c44e --- /dev/null +++ b/templates/emails/transactional/hotmail-complaint.html @@ -0,0 +1,33 @@ +{% extends "base.html" %} + +{% block content %} + {% call text() %} + This is SimpleLogin team.
+ Hotmail has informed us about an email sent to {{ alias.email }} that might have been marked as spam. + {% endcall %} + + {% call text() %} + Putting a forwarded email into Spam affects SimpleLogin email delivery, has a negative effect for all users and + is a violation of our terms and condition. + {% endcall %} + + {% call text() %} + If that’s the case, please disable the alias instead if you don't want to receive the emails sent to this alias. + {% endcall %} + + {% call text() %} + If SimpleLogin isn’t useful for you, please know that you can simply delete your account on the Settings page. + {% endcall %} + + {% call text() %} + Looking to hear back from you. + {% endcall %} + + {% call text() %} + Best,
+ SimpleLogin Team. + {% endcall %} + +{% endblock %} + + diff --git a/templates/emails/transactional/hotmail-complaint.txt.jinja2 b/templates/emails/transactional/hotmail-complaint.txt.jinja2 new file mode 100644 index 00000000..1e8d611e --- /dev/null +++ b/templates/emails/transactional/hotmail-complaint.txt.jinja2 @@ -0,0 +1,17 @@ +Hi, + +This is SimpleLogin team. + +Hotmail has informed us about an email sent to {{ alias.email }} that might have been marked as spam. + +Putting a forwarded email into Spam affects SimpleLogin email delivery, has a negative effect for all users and + is a violation of our terms and condition. + +If that’s the case, please disable the alias instead if you don't want to receive the emails sent to this alias. + +If SimpleLogin isn’t useful for you, please know that you can simply delete your account on the Settings page. + +Looking to hear back from you. + +Best, +SimpleLogin Team. \ No newline at end of file