do not send bounce to IgnoreBounceSender
This commit is contained in:
parent
6dac717c75
commit
fb29503b81
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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")
|
||||||
|
|
Loading…
Reference in New Issue