Merge pull request #21246 from phot0n/minor-fixes-email
fix: minor fixes email
This commit is contained in:
commit
76c3cd3f9c
8 changed files with 57 additions and 110 deletions
|
|
@ -508,7 +508,7 @@
|
|||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:!doc.domain && doc.enable_outgoing",
|
||||
"depends_on": "eval:!doc.domain && doc.enable_outgoing && doc.enable_incoming && doc.use_imap",
|
||||
"fieldname": "append_emails_to_sent_folder",
|
||||
"fieldtype": "Check",
|
||||
"hide_days": 1,
|
||||
|
|
@ -616,7 +616,7 @@
|
|||
"icon": "fa fa-inbox",
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2022-12-28 14:56:18.754804",
|
||||
"modified": "2023-06-05 15:03:08.538819",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Email",
|
||||
"name": "Email Account",
|
||||
|
|
@ -639,4 +639,4 @@
|
|||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
}
|
||||
}
|
||||
|
|
@ -386,7 +386,7 @@ class EmailAccount(Document):
|
|||
"from_site_config": {"default": True},
|
||||
"no_smtp_authentication": {
|
||||
"conf_names": ("disable_mail_smtp_authentication",),
|
||||
"default": 0,
|
||||
"default": 0,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -652,21 +652,16 @@ class EmailAccount(Document):
|
|||
frappe.throw(_("Automatic Linking can be activated only for one Email Account."))
|
||||
|
||||
def append_email_to_sent_folder(self, message):
|
||||
email_server = None
|
||||
try:
|
||||
email_server = self.get_incoming_server(in_receive=True)
|
||||
except Exception:
|
||||
self.log_error("Email Connection Error")
|
||||
|
||||
if not email_server:
|
||||
if not (self.enable_incoming and self.use_imap):
|
||||
# don't try appending if enable incoming and imap is not set
|
||||
return
|
||||
|
||||
if email_server.imap:
|
||||
try:
|
||||
message = safe_encode(message)
|
||||
email_server.imap.append("Sent", "\\Seen", imaplib.Time2Internaldate(time.time()), message)
|
||||
except Exception:
|
||||
self.log_error("Unable to add to Sent folder")
|
||||
try:
|
||||
email_server = self.get_incoming_server(in_receive=True)
|
||||
message = safe_encode(message)
|
||||
email_server.imap.append("Sent", "\\Seen", imaplib.Time2Internaldate(time.time()), message)
|
||||
except Exception:
|
||||
self.log_error("Unable to add to Sent folder")
|
||||
|
||||
def get_oauth_token(self):
|
||||
if self.auth_method == "OAuth":
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@
|
|||
},
|
||||
{
|
||||
"default": "0",
|
||||
"depends_on": "eval:doc.use_imap",
|
||||
"fieldname": "append_emails_to_sent_folder",
|
||||
"fieldtype": "Check",
|
||||
"label": "Append Emails to Sent Folder"
|
||||
|
|
@ -133,7 +134,7 @@
|
|||
"link_fieldname": "domain"
|
||||
}
|
||||
],
|
||||
"modified": "2022-08-19 12:55:06.434541",
|
||||
"modified": "2023-06-05 12:55:06.434541",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Email",
|
||||
"name": "Email Domain",
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
frappe.ui.form.on("Email Queue", {
|
||||
refresh: function (frm) {
|
||||
if (["Not Sent", "Partially Sent"].indexOf(frm.doc.status) != -1) {
|
||||
if (["Not Sent", "Partially Sent"].includes(frm.doc.status)) {
|
||||
let button = frm.add_custom_button("Send Now", function () {
|
||||
frappe.call({
|
||||
method: "frappe.email.doctype.email_queue.email_queue.send_now",
|
||||
|
|
@ -16,9 +16,7 @@ frappe.ui.form.on("Email Queue", {
|
|||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (["Error", "Partially Errored"].indexOf(frm.doc.status) != -1) {
|
||||
} else if (frm.doc.status == "Error") {
|
||||
let button = frm.add_custom_button("Retry Sending", function () {
|
||||
frm.call({
|
||||
method: "retry_sending",
|
||||
|
|
@ -26,10 +24,8 @@ frappe.ui.form.on("Email Queue", {
|
|||
name: frm.doc.name,
|
||||
},
|
||||
btn: button,
|
||||
callback: function (r) {
|
||||
if (!r.exc) {
|
||||
frm.set_value("status", "Not Sent");
|
||||
}
|
||||
callback: function () {
|
||||
frm.reload_doc();
|
||||
},
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -55,12 +55,14 @@
|
|||
"default": "Not Sent",
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 1,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Status",
|
||||
"options": "\nNot Sent\nSending\nSent\nError\nExpired"
|
||||
"options": "Not Sent\nSending\nSent\nPartially Sent\nError\nExpired"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.error",
|
||||
"fieldname": "error",
|
||||
"fieldtype": "Code",
|
||||
"label": "Error"
|
||||
|
|
@ -152,7 +154,7 @@
|
|||
"idx": 1,
|
||||
"in_create": 1,
|
||||
"links": [],
|
||||
"modified": "2023-03-16 12:15:17.850292",
|
||||
"modified": "2023-06-08 15:31:52.789186",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Email",
|
||||
"name": "Email Queue",
|
||||
|
|
|
|||
|
|
@ -123,31 +123,33 @@ class EmailQueue(Document):
|
|||
|
||||
return True
|
||||
|
||||
def send(self, is_background_task: bool = False, smtp_server_instance: SMTPServer = None):
|
||||
def send(self, smtp_server_instance: SMTPServer = None):
|
||||
"""Send emails to recipients."""
|
||||
if not self.can_send_now():
|
||||
return
|
||||
|
||||
with SendMailContext(self, is_background_task, smtp_server_instance) as ctx:
|
||||
with SendMailContext(self, smtp_server_instance) as ctx:
|
||||
message = None
|
||||
for recipient in self.recipients:
|
||||
if not recipient.is_mail_to_be_sent():
|
||||
if recipient.is_mail_sent():
|
||||
continue
|
||||
|
||||
message = ctx.build_message(recipient.recipient)
|
||||
method = get_hook_method("override_email_send")
|
||||
if method:
|
||||
if method := get_hook_method("override_email_send"):
|
||||
method(self, self.sender, recipient.recipient, message)
|
||||
else:
|
||||
if not frappe.flags.in_test:
|
||||
ctx.smtp_session.sendmail(from_addr=self.sender, to_addrs=recipient.recipient, msg=message)
|
||||
ctx.add_to_sent_list(recipient)
|
||||
ctx.smtp_server.session.sendmail(
|
||||
from_addr=self.sender, to_addrs=recipient.recipient, msg=message
|
||||
)
|
||||
|
||||
ctx.update_recipient_status_to_sent(recipient)
|
||||
|
||||
if frappe.flags.in_test:
|
||||
frappe.flags.sent_mail = message
|
||||
return
|
||||
|
||||
if ctx.email_account_doc.append_emails_to_sent_folder and ctx.sent_to:
|
||||
if ctx.email_account_doc.append_emails_to_sent_folder:
|
||||
ctx.email_account_doc.append_email_to_sent_folder(message)
|
||||
|
||||
@staticmethod
|
||||
|
|
@ -177,24 +179,22 @@ class EmailQueue(Document):
|
|||
|
||||
|
||||
@task(queue="short")
|
||||
def send_mail(email_queue_name, is_background_task=False, smtp_server_instance: SMTPServer = None):
|
||||
def send_mail(email_queue_name, smtp_server_instance: SMTPServer = None):
|
||||
"""This is equivalent to EmailQueue.send.
|
||||
|
||||
This provides a way to make sending mail as a background job.
|
||||
"""
|
||||
record = EmailQueue.find(email_queue_name)
|
||||
record.send(is_background_task=is_background_task, smtp_server_instance=smtp_server_instance)
|
||||
record.send(smtp_server_instance=smtp_server_instance)
|
||||
|
||||
|
||||
class SendMailContext:
|
||||
def __init__(
|
||||
self,
|
||||
queue_doc: Document,
|
||||
is_background_task: bool = False,
|
||||
smtp_server_instance: SMTPServer = None,
|
||||
):
|
||||
self.queue_doc: EmailQueue = queue_doc
|
||||
self.is_background_task = is_background_task
|
||||
self.email_account_doc = queue_doc.get_email_account()
|
||||
|
||||
self.smtp_server = smtp_server_instance or self.email_account_doc.get_smtp_server()
|
||||
|
|
@ -203,7 +203,9 @@ class SendMailContext:
|
|||
# Note: smtp session will have to be manually closed
|
||||
self.retain_smtp_session = bool(smtp_server_instance)
|
||||
|
||||
self.sent_to = [rec.recipient for rec in self.queue_doc.recipients if rec.is_mail_sent()]
|
||||
self.sent_to_atleast_one_recipient = any(
|
||||
rec.recipient for rec in self.queue_doc.recipients if rec.is_mail_sent()
|
||||
)
|
||||
|
||||
def __enter__(self):
|
||||
self.queue_doc.update_status(status="Sending", commit=True)
|
||||
|
|
@ -217,53 +219,35 @@ class SendMailContext:
|
|||
smtplib.SMTPHeloError,
|
||||
JobTimeoutException,
|
||||
]
|
||||
trace = "".join(traceback.format_tb(exc_tb)) if exc_tb else None
|
||||
|
||||
if not self.retain_smtp_session:
|
||||
self.smtp_server.quit()
|
||||
|
||||
self.log_exception(exc_type, exc_val, exc_tb)
|
||||
|
||||
if exc_type in exceptions:
|
||||
email_status = "Partially Sent" if self.sent_to else "Not Sent"
|
||||
self.queue_doc.update_status(status=email_status, commit=True)
|
||||
elif exc_type:
|
||||
if self.queue_doc.retry < get_email_retry_limit():
|
||||
update_fields = {"status": "Not Sent", "retry": self.queue_doc.retry + 1}
|
||||
else:
|
||||
update_fields = {"status": (self.sent_to and "Partially Errored") or "Error"}
|
||||
self.queue_doc.update_status(**update_fields, commit=True)
|
||||
else:
|
||||
email_status = self.is_mail_sent_to_all() and "Sent"
|
||||
email_status = email_status or (self.sent_to and "Partially Sent") or "Not Sent"
|
||||
|
||||
update_fields = {
|
||||
"status": email_status,
|
||||
"email_account": self.email_account_doc.name
|
||||
if self.email_account_doc.is_exists_in_db()
|
||||
else None,
|
||||
"status": "Partially Sent" if self.sent_to_atleast_one_recipient else "Not Sent",
|
||||
"error": trace,
|
||||
}
|
||||
self.queue_doc.update_status(**update_fields, commit=True)
|
||||
elif exc_type:
|
||||
update_fields = {"error": trace}
|
||||
if self.queue_doc.retry < get_email_retry_limit():
|
||||
update_fields.update(
|
||||
{
|
||||
"status": "Partially Sent" if self.sent_to_atleast_one_recipient else "Not Sent",
|
||||
"retry": self.queue_doc.retry + 1,
|
||||
}
|
||||
)
|
||||
else:
|
||||
update_fields.update({"status": "Error"})
|
||||
else:
|
||||
update_fields = {"status": "Sent"}
|
||||
|
||||
def log_exception(self, exc_type, exc_val, exc_tb):
|
||||
if exc_type:
|
||||
traceback_string = "".join(traceback.format_tb(exc_tb))
|
||||
traceback_string += f"\n Queue Name: {self.queue_doc.name}"
|
||||
self.queue_doc.update_status(**update_fields, commit=True)
|
||||
|
||||
self.queue_doc.log_error("Email sending failed", traceback_string)
|
||||
|
||||
@property
|
||||
def smtp_session(self):
|
||||
if frappe.flags.in_test:
|
||||
return
|
||||
return self.smtp_server.session
|
||||
|
||||
def add_to_sent_list(self, recipient):
|
||||
# Update recipient status
|
||||
def update_recipient_status_to_sent(self, recipient):
|
||||
self.sent_to_atleast_one_recipient = True
|
||||
recipient.update_db(status="Sent", commit=True)
|
||||
self.sent_to.append(recipient.recipient)
|
||||
|
||||
def is_mail_sent_to_all(self):
|
||||
return sorted(self.sent_to) == sorted(rec.recipient for rec in self.queue_doc.recipients)
|
||||
|
||||
def get_message_object(self, message):
|
||||
return Parser(policy=SMTPUTF8).parsestr(message)
|
||||
|
|
@ -379,7 +363,7 @@ def retry_sending(name):
|
|||
doc = frappe.get_doc("Email Queue", name)
|
||||
doc.check_permission()
|
||||
|
||||
if doc and (doc.status == "Error" or doc.status == "Partially Errored"):
|
||||
if doc and doc.status == "Error":
|
||||
doc.status = "Not Sent"
|
||||
for d in doc.recipients:
|
||||
if d.status != "Sent":
|
||||
|
|
|
|||
|
|
@ -154,7 +154,6 @@ def flush(from_test=False):
|
|||
frappe.enqueue(
|
||||
method=send_mail,
|
||||
email_queue_name=row.name,
|
||||
is_background_task=not from_test,
|
||||
now=from_test,
|
||||
job_name=job_name,
|
||||
queue="short",
|
||||
|
|
|
|||
|
|
@ -13,36 +13,6 @@ class InvalidEmailCredentials(frappe.ValidationError):
|
|||
pass
|
||||
|
||||
|
||||
def send(email, append_to=None, retry=1):
|
||||
"""Deprecated: Send the message or add it to Outbox Email"""
|
||||
|
||||
def _send(retry):
|
||||
from frappe.email.doctype.email_account.email_account import EmailAccount
|
||||
|
||||
try:
|
||||
email_account = EmailAccount.find_outgoing(match_by_doctype=append_to)
|
||||
smtpserver = email_account.get_smtp_server()
|
||||
|
||||
# validate is called in as_string
|
||||
email_body = email.as_string()
|
||||
|
||||
smtpserver.sess.sendmail(email.sender, email.recipients + (email.cc or []), email_body)
|
||||
except smtplib.SMTPSenderRefused:
|
||||
frappe.throw(_("Invalid login or password"), title="Email Failed")
|
||||
raise
|
||||
except smtplib.SMTPRecipientsRefused:
|
||||
frappe.msgprint(_("Invalid recipient address"), title="Email Failed")
|
||||
raise
|
||||
except (smtplib.SMTPServerDisconnected, smtplib.SMTPAuthenticationError):
|
||||
if not retry:
|
||||
raise
|
||||
else:
|
||||
retry = retry - 1
|
||||
_send(retry)
|
||||
|
||||
_send(retry)
|
||||
|
||||
|
||||
class SMTPServer:
|
||||
def __init__(
|
||||
self,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue