fix: stop mail loops from bounces and autoresponders - #3628
Open
aerodeval wants to merge 1 commit into
Open
Conversation
Inbound mail was only screened with the X-Auto-Generated header, which only helpdesk's own acks set. A real bounce or out-of-office therefore reached ticket creation and could start three separate loops: the ack in HD Ticket.after_insert replies to raised_by (the address that just bounced), threading onto a portal ticket makes frappe CC the parent doc's owner on every inbound mail, and an account with enable_auto_reply answers mailer-daemon directly. Detect machine-generated mail by the standard markers instead: RFC 3834 Auto-Submitted, the RFC 3464 multipart/report delivery-status type, and the RFC 5321 null return-path. Matches are routed to handle_bad_emails so they land in Unhandled Email rather than disappearing -- the fetch has already marked them seen either way. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #3628 +/- ##
===========================================
+ Coverage 68.57% 68.93% +0.36%
===========================================
Files 140 144 +4
Lines 9181 9442 +261
===========================================
+ Hits 6296 6509 +213
- Misses 2885 2933 +48 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
RitvikSardana
marked this pull request as ready for review
July 30, 2026 10:53
|
Tick the box to add this pull request to the merge queue (same as
|
Confidence Score: 5/5The PR appears safe to merge. The classifier preserves ordinary and explicitly human-submitted mail while diverting recognized automated messages through the existing per-message error-handling path. Reviews (1): Last reviewed commit: "fix: stop mail loops from bounces and au..." | Re-trigger Greptile |
Member
Author
|
@RitvikSardana have to test one more thing, do not merge yet |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Inbound mail is only screened with the
X-Auto-Generatedheader, which nothing but helpdesk's own acknowledgement emails set. Real bounces and out-of-office replies pass straight through into ticket creation, where they can start a mail loop with the sending MTA.Once a machine-generated mail becomes a ticket or a communication, three separate paths can reply to it:
HD Ticket.after_insertsends the acknowledgement toraised_by, i.e. the address that just bounced.mail_cc) on every inbound mail — the same dead address.enable_auto_reply— an account with auto-reply on answersmailer-daemondirectly.Each reply bounces again, which creates another inbound mail, and so on.
Changes
helpdesk/overrides/email_account.py— newauto_generated_reason(msg)identifies machine-generated mail by the standard markers instead of relying on our own header:Auto-Submitted— anything butno(parameters after the value are tolerated, e.g.no; owner=...)multipart/report; report-type=delivery-status— catches a DSN even where no MTA added aReturn-Path(POP3, Frappe Mail)<>) — which bounces MUST carryX-Auto-Generatedis kept, so our own acks are still caughtMatches now go to
handle_bad_emails(uid, message, reason)and land in Unhandled Email with the reason recorded, instead of being silently dropped by a barecontinue. The fetch has already marked them seen either way, so this costs nothing and leaves a trace when a real mail is misclassified.Testing
helpdesk/overrides/test_email_account.py— 8 unit tests overauto_generated_reasonwith real message fixtures (Gmail DSN, out-of-office, a DSN with noReturn-Path, and genuine customer replies), asserting bounces are dropped and human mail is kept, including theAuto-Submitted: nocases.Note
These are pure stdlib
emailtests with no site fixtures. They currently need frappe importable, since the module imports it at the top; the function itself touches none of it.