email_mirror: Drop missed-message emails which are autogenerated.

Emails to missed-message email addressees which are marked
"auto-replied" are clearly auto-replies, and will not contribute
usefully to the conversation.  We also ignore "auto-generated" emails
to missed-message addresses, as they must actually be auto-replies
which are misclassifying themselves, as missed-message addresses are
not meant to be targets for any auto-generated emails.

We accept auto-generated and auto-replied emails to stream incoming
email addresses, as auto-generated emails to those are clearly useful,
and auto-replied emails are unexpected enough to allow (given that
Zulip does not produce outgoing emails From: stream email addresses).
This commit is contained in:
Alex Vandiver
2025-09-26 04:07:18 +00:00
committed by Tim Abbott
parent f2a11c5858
commit 3538455ca8
2 changed files with 42 additions and 0 deletions

View File

@@ -467,6 +467,11 @@ def process_stream_message(to: str, message: EmailMessage) -> None:
def process_missed_message(to: str, message: EmailMessage) -> None:
auto_submitted = message.get("Auto-Submitted", "")
if auto_submitted in ("auto-replied", "auto-generated"):
logger.info("Dropping %s message from %s", auto_submitted, message.get("From"))
return
mm_address = get_usable_missed_message_address(to)
mm_address.increment_times_used()

View File

@@ -1587,6 +1587,43 @@ class TestMissedMessageEmailMessages(ZulipTestCase):
for i in range(5):
process_missed_message(mm_address, incoming_valid_message)
def test_autoreply(self) -> None:
self.login("hamlet")
othello = self.example_user("othello")
result = self.client_post(
"/json/messages",
{
"type": "private",
"content": "test_receive_missed_message_email_messages",
"to": orjson.dumps([othello.id]).decode(),
},
)
self.assert_json_success(result)
usermessage = most_recent_usermessage(othello)
mm_address = create_missed_message_address(othello, usermessage.message)
incoming_autoreply = EmailMessage()
incoming_autoreply.set_content("An auto-reply")
incoming_autoreply["Subject"] = "TestMissedMessageEmailMessages subject"
incoming_autoreply["From"] = self.example_email("othello")
incoming_autoreply["To"] = mm_address
incoming_autoreply["Reply-to"] = self.example_email("othello")
incoming_autoreply["Auto-Submitted"] = "auto-replied"
hamlet = self.example_user("hamlet")
message = most_recent_message(hamlet)
with self.assert_database_query_count(0), self.assertLogs(logger_name, level="INFO") as m:
process_message(incoming_autoreply)
self.assertEqual(
m.output,
[f"INFO:{logger_name}:Dropping auto-replied message from othello@zulip.com"],
)
# It should get dropped, so the most recent message is unchanged
self.assertEqual(message, most_recent_message(hamlet))
class TestEmptyGatewaySetting(ZulipTestCase):
def test_missed_message(self) -> None: