From bf70022859df85ee3bda8504da80ba6d9f43e26a Mon Sep 17 00:00:00 2001 From: Hussain Nagaria Date: Fri, 17 Oct 2025 13:49:39 +0530 Subject: [PATCH 1/4] fix: consider sent or received for duplicate check --- frappe/email/receive.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frappe/email/receive.py b/frappe/email/receive.py index 6733c2d246..64a6838af0 100644 --- a/frappe/email/receive.py +++ b/frappe/email/receive.py @@ -720,7 +720,9 @@ class InboundMail(Email): if not self.message_id: return - return Communication.find_one_by_filters(message_id=self.message_id, order_by="creation DESC") + return Communication.find_one_by_filters( + message_id=self.message_id, sent_or_received="Received", order_by="creation DESC" + ) def is_sender_same_as_receiver(self): return self.from_email == self.email_account.email_id From a164ebf58373aa071c8c03013b0c53159c9f7502 Mon Sep 17 00:00:00 2001 From: Hussain Nagaria Date: Fri, 17 Oct 2025 15:06:13 +0530 Subject: [PATCH 2/4] test: mark inbound email as received --- frappe/email/doctype/email_account/test_email_account.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/email/doctype/email_account/test_email_account.py b/frappe/email/doctype/email_account/test_email_account.py index af5749b309..96a02c86dd 100644 --- a/frappe/email/doctype/email_account/test_email_account.py +++ b/frappe/email/doctype/email_account/test_email_account.py @@ -523,7 +523,7 @@ class TestInboundMail(IntegrationTestCase): mail_content = self.get_test_mail(fname="incoming-1.raw") message_id = Email(mail_content).message_id # Create new communication record in DB - communication = self.new_communication(message_id=message_id) + communication = self.new_communication(message_id=message_id, sent_or_received="Received") email_account = frappe.get_doc("Email Account", "_Test Email Account 1") inbound_mail = InboundMail(mail_content, email_account, 12345, 1) From ab9635d387bfe2526188f27559691da29720289c Mon Sep 17 00:00:00 2001 From: Hussain Nagaria Date: Fri, 17 Oct 2025 18:22:29 +0530 Subject: [PATCH 3/4] fix: get the latest communication for reply-to first --- frappe/email/receive.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frappe/email/receive.py b/frappe/email/receive.py index 64a6838af0..aeca829199 100644 --- a/frappe/email/receive.py +++ b/frappe/email/receive.py @@ -768,7 +768,9 @@ class InboundMail(Email): if not self.is_reply(): return "" - communication = Communication.find_one_by_filters(message_id=self.in_reply_to) + communication = Communication.find_one_by_filters( + message_id=self.in_reply_to, order_by="creation DESC" + ) if not communication: if self.parent_email_queue() and self.parent_email_queue().communication: communication = Communication.find(self.parent_email_queue().communication, ignore_error=True) From 289391bfd3e77e953ca0357fc92d21eda6374059 Mon Sep 17 00:00:00 2001 From: Hussain Nagaria Date: Mon, 27 Oct 2025 22:48:44 +0530 Subject: [PATCH 4/4] fix: deduplicate timeline links for system-to-system emails --- frappe/core/doctype/communication/communication.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/frappe/core/doctype/communication/communication.py b/frappe/core/doctype/communication/communication.py index 2c5cf4889a..88d1e5c32f 100644 --- a/frappe/core/doctype/communication/communication.py +++ b/frappe/core/doctype/communication/communication.py @@ -416,6 +416,13 @@ class Communication(Document, CommunicationEmailMixin): # Timeline Links def set_timeline_links(self): + # Skip timeline links if a "Sent" communication already exists + # else will create duplicate timeline entries + if self.sent_or_received == "Received" and self.find_one_by_filters( + message_id=self.message_id, sent_or_received="Sent" + ): + return + contacts = [] create_contact_enabled = self.email_account and frappe.db.get_value( "Email Account", self.email_account, "create_contact"