do not send bounce to IgnoreBounceSender

This commit is contained in:
Son Nguyen Kim 2021-08-02 11:33:58 +02:00
parent 6dac717c75
commit fb29503b81
4 changed files with 47 additions and 8 deletions

View File

@ -8,6 +8,9 @@ E205 = "250 SL E205 bounce handled"
# out of office status # out of office status
E206 = "250 SL E206 Out of office" 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"
# 4** errors # 4** errors
# E401 = "421 SL E401 Retry later" # E401 = "421 SL E401 Retry later"
E402 = "421 SL E402 Encryption failed - Retry later" E402 = "421 SL E402 Encryption failed - Retry later"

View File

@ -58,6 +58,7 @@ from app.models import (
Alias, Alias,
EmailLog, EmailLog,
TransactionalEmail, TransactionalEmail,
IgnoreBounceSender,
) )
from app.utils import ( from app.utils import (
random_string, random_string,
@ -1213,3 +1214,11 @@ def get_queue_id(msg: Message) -> Optional[str]:
with_esmtps = received_header[search_result.start() : search_result.end()] with_esmtps = received_header[search_result.start() : search_result.end()]
return with_esmtps[len("with ESMTPS id ") :] return with_esmtps[len("with ESMTPS id ") :]
def should_ignore_bounce(mail_from: str) -> bool:
if IgnoreBounceSender.get_by(mail_from=mail_from):
LOG.w("do not send back bounce report to %s", mail_from)
return True
return False

View File

@ -111,6 +111,7 @@ from app.email_utils import (
sl_sendmail, sl_sendmail,
sanitize_header, sanitize_header,
get_queue_id, get_queue_id,
should_ignore_bounce,
) )
from app.extensions import db from app.extensions import db
from app.log import LOG, set_message_id from app.log import LOG, set_message_id
@ -540,13 +541,19 @@ def handle_forward(envelope, msg: Message, rcpt_to: str) -> List[Tuple[bool, str
alias = try_auto_create(address) alias = try_auto_create(address)
if not alias: if not alias:
LOG.d("alias %s cannot be created on-the-fly, return 550", address) LOG.d("alias %s cannot be created on-the-fly, return 550", address)
return [(False, status.E515)] if should_ignore_bounce(envelope.mail_from):
return [(True, status.E207)]
else:
return [(False, status.E515)]
user = alias.user user = alias.user
if user.disabled: if user.disabled:
LOG.w("User %s disabled, disable forwarding emails for %s", user, alias) LOG.w("User %s disabled, disable forwarding emails for %s", user, alias)
return [(False, status.E504)] if should_ignore_bounce(envelope.mail_from):
return [(True, status.E207)]
else:
return [(False, status.E504)]
# mail_from = envelope.mail_from # mail_from = envelope.mail_from
# for mb in alias.mailboxes: # for mb in alias.mailboxes:
@ -588,7 +595,10 @@ def handle_forward(envelope, msg: Message, rcpt_to: str) -> List[Tuple[bool, str
# no valid mailbox # no valid mailbox
if not mailboxes: if not mailboxes:
return [(False, status.E516)] if should_ignore_bounce(envelope.mail_from):
return [(True, status.E207)]
else:
return [(False, status.E516)]
# no need to create a copy of message # no need to create a copy of message
for mailbox in mailboxes: for mailbox in mailboxes:
@ -618,8 +628,11 @@ def forward_email_to_mailbox(
LOG.d("Forward %s -> %s -> %s", contact, alias, mailbox) LOG.d("Forward %s -> %s -> %s", contact, alias, mailbox)
if mailbox.disabled: if mailbox.disabled:
LOG.debug("%s disabled, do not forward") LOG.d("%s disabled, do not forward")
return False, status.E518 if should_ignore_bounce(envelope.mail_from):
return True, status.E207
else:
return False, status.E518
# sanity check: make sure mailbox is not actually an alias # sanity check: make sure mailbox is not actually an alias
if get_email_domain_part(alias.email) == get_email_domain_part(mailbox.email): if get_email_domain_part(alias.email) == get_email_domain_part(mailbox.email):
@ -819,7 +832,10 @@ def forward_email_to_mailbox(
alias, alias,
mailbox, mailbox,
) )
return False, status.E521 if should_ignore_bounce(envelope.mail_from):
return True, status.E207
else:
return False, status.E521
else: else:
db.session.commit() db.session.commit()
return True, status.E200 return True, status.E200
@ -1707,7 +1723,10 @@ def handle(envelope: Envelope) -> str:
if rate_limited(mail_from, rcpt_tos): if rate_limited(mail_from, rcpt_tos):
LOG.w("Rate Limiting applied for mail_from:%s rcpt_tos:%s", mail_from, rcpt_tos) LOG.w("Rate Limiting applied for mail_from:%s rcpt_tos:%s", mail_from, rcpt_tos)
return status.E522 if should_ignore_bounce(envelope.mail_from):
return status.E207
else:
return status.E522
# Handle "out of office" auto notice. An automatic response is sent for every forwarded email # Handle "out of office" auto notice. An automatic response is sent for every forwarded email
# todo: remove logging # todo: remove logging

View File

@ -28,9 +28,10 @@ from app.email_utils import (
decode_text, decode_text,
parse_id_from_bounce, parse_id_from_bounce,
get_queue_id, get_queue_id,
should_ignore_bounce,
) )
from app.extensions import db from app.extensions import db
from app.models import User, CustomDomain, Alias, Contact, EmailLog from app.models import User, CustomDomain, Alias, Contact, EmailLog, IgnoreBounceSender
# flake8: noqa: E101, W191 # flake8: noqa: E101, W191
from tests.utils import login from tests.utils import login
@ -740,3 +741,10 @@ def test_get_queue_id():
) )
assert get_queue_id(msg) == "4FxQmw1DXdz2vK2" assert get_queue_id(msg) == "4FxQmw1DXdz2vK2"
def test_should_ignore_bounce(flask_client):
assert not should_ignore_bounce("not-exist")
IgnoreBounceSender.create(mail_from="to-ignore@example.com")
assert should_ignore_bounce("to-ignore@example.com")