From 2bbf72061c7e41f3505c1338e7b0de3c0d895bf4 Mon Sep 17 00:00:00 2001 From: sokumon Date: Fri, 11 Jul 2025 18:45:20 +0530 Subject: [PATCH 1/4] fix: dont let email queue stay in Sending status --- frappe/email/queue.py | 25 +++++++++++++++++++++++++ frappe/hooks.py | 1 + 2 files changed, 26 insertions(+) diff --git a/frappe/email/queue.py b/frappe/email/queue.py index cd6de1ff81..536ae0d680 100755 --- a/frappe/email/queue.py +++ b/frappe/email/queue.py @@ -1,5 +1,6 @@ # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors # License: MIT. See LICENSE +from datetime import timedelta import frappe from frappe import _, msgprint @@ -177,3 +178,27 @@ def get_queue(): {"now": now_datetime()}, as_dict=True, ) + + +def mark_sending_emails_as_not_sent(): + emails_in_sending = frappe.get_all( + "Email Queue", filters={"status": "Sending"}, fields=["name", "modified"] + ) + for e in emails_in_sending: + if now_datetime() - e["modified"] > timedelta(minutes=15): + update_fields = {} + email_queue = frappe.get_doc("Email Queue", e["name"]) + sent_to_atleast_one_recipient = any( + rec.recipient for rec in email_queue.recipients if rec.is_mail_sent() + ) + if email_queue.retry < cint(frappe.db.get_system_setting("email_retry_limit")) or 3: + update_fields.update( + { + "status": "Partially Sent" if sent_to_atleast_one_recipient else "Not Sent", + "retry": email_queue.retry + 1, + } + ) + else: + update_fields.update({"status": "Error"}) + update_fields.update({"error": frappe.get_traceback()}) + email_queue.update_status(**update_fields, commit=True) diff --git a/frappe/hooks.py b/frappe/hooks.py index bebb1f7e73..f6458378d5 100644 --- a/frappe/hooks.py +++ b/frappe/hooks.py @@ -217,6 +217,7 @@ scheduler_events = { }, "all": [ "frappe.email.queue.flush", + "frappe.email.queue.mark_sending_emails_as_not_sent", "frappe.monitor.flush", "frappe.integrations.doctype.google_calendar.google_calendar.sync", ], From 74b4acacd4ced451ae11845a4047d3ae5443b190 Mon Sep 17 00:00:00 2001 From: sokumon Date: Mon, 14 Jul 2025 18:30:37 +0530 Subject: [PATCH 2/4] fix: better name for the retry job --- frappe/email/queue.py | 2 +- frappe/hooks.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/email/queue.py b/frappe/email/queue.py index 536ae0d680..449764b41d 100755 --- a/frappe/email/queue.py +++ b/frappe/email/queue.py @@ -180,7 +180,7 @@ def get_queue(): ) -def mark_sending_emails_as_not_sent(): +def retry_sending_emails(): emails_in_sending = frappe.get_all( "Email Queue", filters={"status": "Sending"}, fields=["name", "modified"] ) diff --git a/frappe/hooks.py b/frappe/hooks.py index f6458378d5..2acbe4f08c 100644 --- a/frappe/hooks.py +++ b/frappe/hooks.py @@ -217,7 +217,7 @@ scheduler_events = { }, "all": [ "frappe.email.queue.flush", - "frappe.email.queue.mark_sending_emails_as_not_sent", + "frappe.email.queue.retry_sending_emails", "frappe.monitor.flush", "frappe.integrations.doctype.google_calendar.google_calendar.sync", ], From 6ff0c937d785fc190bf42b53a23c873fb2a358ba Mon Sep 17 00:00:00 2001 From: sokumon Date: Tue, 15 Jul 2025 17:44:53 +0530 Subject: [PATCH 3/4] fix: use get_retry method and change error message --- frappe/email/queue.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frappe/email/queue.py b/frappe/email/queue.py index 449764b41d..ee3c3737ed 100755 --- a/frappe/email/queue.py +++ b/frappe/email/queue.py @@ -4,6 +4,7 @@ from datetime import timedelta import frappe from frappe import _, msgprint +from frappe.email.doctype.email_queue.email_queue import get_email_retry_limit from frappe.utils import cint, cstr, get_url, now_datetime from frappe.utils.data import getdate from frappe.utils.verified_command import get_signed_params, verify_request @@ -191,7 +192,7 @@ def retry_sending_emails(): sent_to_atleast_one_recipient = any( rec.recipient for rec in email_queue.recipients if rec.is_mail_sent() ) - if email_queue.retry < cint(frappe.db.get_system_setting("email_retry_limit")) or 3: + if email_queue.retry < get_email_retry_limit(): update_fields.update( { "status": "Partially Sent" if sent_to_atleast_one_recipient else "Not Sent", @@ -200,5 +201,5 @@ def retry_sending_emails(): ) else: update_fields.update({"status": "Error"}) - update_fields.update({"error": frappe.get_traceback()}) + update_fields.update({"error": "Retry limit execedded"}) email_queue.update_status(**update_fields, commit=True) From 8e9187483c2e2e522e8a1ba76be9d56f1b0b1a57 Mon Sep 17 00:00:00 2001 From: sokumon Date: Tue, 15 Jul 2025 18:03:41 +0530 Subject: [PATCH 4/4] fix: avoid circular import --- frappe/email/queue.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/frappe/email/queue.py b/frappe/email/queue.py index ee3c3737ed..7cd8e97292 100755 --- a/frappe/email/queue.py +++ b/frappe/email/queue.py @@ -4,7 +4,6 @@ from datetime import timedelta import frappe from frappe import _, msgprint -from frappe.email.doctype.email_queue.email_queue import get_email_retry_limit from frappe.utils import cint, cstr, get_url, now_datetime from frappe.utils.data import getdate from frappe.utils.verified_command import get_signed_params, verify_request @@ -192,7 +191,7 @@ def retry_sending_emails(): sent_to_atleast_one_recipient = any( rec.recipient for rec in email_queue.recipients if rec.is_mail_sent() ) - if email_queue.retry < get_email_retry_limit(): + if email_queue.retry < cint(frappe.db.get_system_setting("email_retry_limit")) or 3: update_fields.update( { "status": "Partially Sent" if sent_to_atleast_one_recipient else "Not Sent", @@ -201,5 +200,5 @@ def retry_sending_emails(): ) else: update_fields.update({"status": "Error"}) - update_fields.update({"error": "Retry limit execedded"}) + update_fields.update({"error": "Retry Limit Exceeded"}) email_queue.update_status(**update_fields, commit=True)