diff --git a/app/config.py b/app/config.py index fb77039f..475a661e 100644 --- a/app/config.py +++ b/app/config.py @@ -382,6 +382,9 @@ PGP_SIGNER = os.environ.get("PGP_SIGNER") # emails that have empty From address is sent from this special reverse-alias NOREPLY = os.environ.get("NOREPLY", f"noreply@{EMAIL_DOMAIN}") +# list of no reply addresses +NOREPLIES = sl_getenv("NOREPLIES", list) or [NOREPLY] + COINBASE_WEBHOOK_SECRET = os.environ.get("COINBASE_WEBHOOK_SECRET") COINBASE_CHECKOUT_ID = os.environ.get("COINBASE_CHECKOUT_ID") COINBASE_API_KEY = os.environ.get("COINBASE_API_KEY") diff --git a/email_handler.py b/email_handler.py index 98dbeb53..25be0ba1 100644 --- a/email_handler.py +++ b/email_handler.py @@ -53,7 +53,7 @@ from flanker.addresslib.address import EmailAddress from sqlalchemy.exc import IntegrityError from sqlalchemy.orm.exc import ObjectDeletedError -from app import pgp_utils, s3 +from app import pgp_utils, s3, config from app.alias_utils import try_auto_create from app.config import ( EMAIL_DOMAIN, @@ -88,14 +88,6 @@ from app.config import ( ALERT_TO_NOREPLY, ) from app.db import Session -from app.handler.dmarc import ( - apply_dmarc_policy_for_reply_phase, - apply_dmarc_policy_for_forward_phase, -) -from app.handler.spamd_result import ( - SpamdResult, - SPFCheckResult, -) from app.email import status, headers from app.email.rate_limit import rate_limited from app.email.spam import get_spam_score @@ -146,6 +138,14 @@ from app.errors import ( VERPReply, CannotCreateContactForReverseAlias, ) +from app.handler.dmarc import ( + apply_dmarc_policy_for_reply_phase, + apply_dmarc_policy_for_forward_phase, +) +from app.handler.spamd_result import ( + SpamdResult, + SPFCheckResult, +) from app.log import LOG, set_message_id from app.models import ( Alias, @@ -2386,7 +2386,7 @@ def handle(envelope: Envelope, msg: Message) -> str: nb_rcpt_tos = len(rcpt_tos) for rcpt_index, rcpt_to in enumerate(rcpt_tos): - if rcpt_to == NOREPLY: + if rcpt_to in config.NOREPLIES: LOG.i("email sent to {} address from {}".format(NOREPLY, mail_from)) send_no_reply_response(mail_from, msg) return status.E200 diff --git a/tests/test_email_handler.py b/tests/test_email_handler.py index 37553967..ab1877c8 100644 --- a/tests/test_email_handler.py +++ b/tests/test_email_handler.py @@ -6,6 +6,7 @@ import pytest from aiosmtpd.smtp import Envelope import email_handler +from app import config from app.config import EMAIL_DOMAIN, ALERT_DMARC_FAILED_REPLY_PHASE from app.db import Session from app.email import headers, status @@ -233,3 +234,28 @@ def test_avoid_add_to_header_already_present_in_cc(): email_handler.add_alias_to_header_if_needed(msg, alias) assert msg[headers.TO] is None assert msg[headers.CC] == alias.email + + +def test_email_sent_to_noreply(flask_client): + msg = EmailMessage() + envelope = Envelope() + envelope.mail_from = "from@domain.test" + envelope.rcpt_tos = [config.NOREPLY] + result = email_handler.handle(envelope, msg) + assert result == status.E200 + + +def test_email_sent_to_noreplies(flask_client): + msg = EmailMessage() + envelope = Envelope() + envelope.mail_from = "from@domain.test" + config.NOREPLIES = ["other-no-reply@sl.test"] + + envelope.rcpt_tos = ["other-no-reply@sl.test"] + result = email_handler.handle(envelope, msg) + assert result == status.E200 + + # NOREPLY isn't used anymore + envelope.rcpt_tos = [config.NOREPLY] + result = email_handler.handle(envelope, msg) + assert result == status.E515