Store the bounced email in email handling.

This commit is contained in:
Son NK 2020-03-14 16:34:23 +01:00
parent c3b85115ca
commit 0bb9830680
4 changed files with 64 additions and 11 deletions

View File

@ -363,3 +363,18 @@ def mailbox_already_used(email: str, user) -> bool:
return True
return False
def get_orig_message_from_bounce(msg: Message) -> Message:
"""parse the original email from Bounce"""
i = 0
for part in msg.walk():
i += 1
# the original message is the 4th part
# 1st part is the root part, multipart/report
# 2nd is text/plain, Postfix log
# ...
# 7th is original message
if i == 7:
return part

View File

@ -37,21 +37,19 @@ from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.parser import Parser
from email.policy import SMTPUTF8
from io import BytesIO
from smtplib import SMTP
from typing import Optional
from aiosmtpd.controller import Controller
import gnupg
from app import pgp_utils, s3
from app.config import (
EMAIL_DOMAIN,
POSTFIX_SERVER,
URL,
ALIAS_DOMAINS,
ADMIN_EMAIL,
SUPPORT_EMAIL,
POSTFIX_SUBMISSION_TLS,
GNUPGHOME,
)
from app.email_utils import (
get_email_name,
@ -65,6 +63,7 @@ from app.email_utils import (
send_cannot_create_domain_alias,
email_belongs_to_alias_domains,
render,
get_orig_message_from_bounce,
)
from app.extensions import db
from app.log import LOG
@ -76,10 +75,10 @@ from app.models import (
Directory,
User,
DeletedAlias,
RefusedEmail,
)
from app.utils import random_string
from server import create_app
from app import pgp_utils
# fix the database connection leak issue
@ -406,7 +405,12 @@ def handle_reply(envelope, smtp: SMTP, msg: Message, rcpt_to: str) -> str:
# in this case Postfix will try to send a bounce report to original sender, which is
# the "reply email"
if envelope.mail_from == "<>":
LOG.error("Bounce when sending to alias %s, user %s", alias, gen_email.user)
LOG.error(
"Bounce when sending to alias %s from %s, user %s",
alias,
forward_email.website_from,
gen_email.user,
)
handle_bounce(
alias, envelope, forward_email, gen_email, msg, smtp, user, mailbox_email
@ -513,7 +517,9 @@ def handle_reply(envelope, smtp: SMTP, msg: Message, rcpt_to: str) -> str:
def handle_bounce(
alias, envelope, forward_email, gen_email, msg, smtp, user, mailbox_email
):
ForwardEmailLog.create(forward_id=forward_email.id, bounced=True)
fel: ForwardEmailLog = ForwardEmailLog.create(
forward_id=forward_email.id, bounced=True
)
db.session.commit()
nb_bounced = ForwardEmailLog.filter_by(
@ -521,6 +527,30 @@ def handle_bounce(
).count()
disable_alias_link = f"{URL}/dashboard/unsubscribe/{gen_email.id}"
# Store the bounced email
random_name = random_string(50)
full_report_path = f"refused-emails/full-{random_name}.eml"
s3.upload_from_bytesio(full_report_path, BytesIO(msg.as_bytes()))
file_path = f"refused-emails/{random_name}.eml"
orig_msg = get_orig_message_from_bounce(msg)
s3.upload_from_bytesio(file_path, BytesIO(orig_msg.as_bytes()))
refused_email = RefusedEmail.create(
path=file_path, full_report_path=full_report_path, user_id=user.id
)
db.session.flush()
fel.refused_email_id = refused_email.id
db.session.commit()
LOG.d("Create refused email %s", refused_email)
refused_email_url = (
URL + f"/dashboard/refused_email?highlight_fel_id=" + str(fel.id)
)
# inform user if this is the first bounced email
if nb_bounced == 1:
LOG.d(
@ -530,7 +560,9 @@ def handle_bounce(
alias,
)
send_email(
mailbox_email,
# TOOD: use mailbox_email instead
user.email,
# mailbox_email,
f"Email from {forward_email.website_from} to {alias} cannot be delivered to your inbox",
render(
"transactional/bounced-email.txt",
@ -539,6 +571,7 @@ def handle_bounce(
website_from=forward_email.website_from,
website_email=forward_email.website_email,
disable_alias_link=disable_alias_link,
refused_email_url=refused_email_url,
),
render(
"transactional/bounced-email.html",
@ -547,8 +580,10 @@ def handle_bounce(
website_from=forward_email.website_from,
website_email=forward_email.website_email,
disable_alias_link=disable_alias_link,
refused_email_url=refused_email_url,
),
bounced_email=msg,
# cannot include bounce email as it can contain spammy text
# bounced_email=msg,
)
# disable the alias the second time email is bounced
elif nb_bounced >= 2:

View File

@ -4,7 +4,9 @@
{{ render_text("Hi " + name) }}
{{ render_text("An email sent to your alias <b>" + alias + "</b> from <b>" + website_email + "</b> was <b>refused</b> (or <em>bounced</em>) by your email provider.") }}
{{ render_text("This is usually due to the email being considered as <b>spam</b> by your email provider. The email is included at the end of this message so you can take a look at its content.") }}
{{ render_text('This is usually due to the email being considered as <b>spam</b> by your email provider.') }}
{{ render_button("View the refused email", refused_email_url) }}
{{ render_text('To avoid spams forwarded by SimpleLogin server, please consider the following options:') }}

View File

@ -3,7 +3,8 @@ Hi {{name}}
An email sent to your alias {{alias}} from {{website_from}} was refused (or bounced) by your email provider.
This is usually due to the email being considered as spam by your email provider.
The email is included at the end of this message so you can take a look at its content.
You can view this email here:
{{ refused_email_url }}
To avoid spams forwarded by SimpleLogin server, please consider the following options: