feat: configurable DSN (#36988)
* feat: configurable `DSN` * chore: validate dsn support on save * fix: DSN validation
This commit is contained in:
parent
5d67826f25
commit
fef9d89ce0
4 changed files with 39 additions and 2 deletions
|
|
@ -78,6 +78,7 @@
|
|||
"smtp_port",
|
||||
"column_break_38",
|
||||
"no_smtp_authentication",
|
||||
"dsn_notify_type",
|
||||
"always_bcc",
|
||||
"signature_section",
|
||||
"add_signature",
|
||||
|
|
@ -754,13 +755,20 @@
|
|||
"ignore_xss_filter": 1,
|
||||
"label": "Reply-To Addresses",
|
||||
"options": "Reply To Address"
|
||||
},
|
||||
{
|
||||
"description": "Select which delivery events should trigger a delivery status notification (DSN) from the SMTP server.",
|
||||
"fieldname": "dsn_notify_type",
|
||||
"fieldtype": "Select",
|
||||
"label": "Delivery Status Notification Type",
|
||||
"options": "\nSUCCESS\nFAILURE\nDELAY\nSUCCESS,FAILURE\nSUCCESS,FAILURE,DELAY\nNEVER"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-inbox",
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"make_attachments_public": 1,
|
||||
"modified": "2026-02-06 11:39:39.412130",
|
||||
"modified": "2026-02-11 16:18:15.572240",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Email",
|
||||
"name": "Email Account",
|
||||
|
|
|
|||
|
|
@ -84,6 +84,9 @@ class EmailAccount(Document):
|
|||
default_incoming: DF.Check
|
||||
default_outgoing: DF.Check
|
||||
domain: DF.Link | None
|
||||
dsn_notify_type: DF.Literal[
|
||||
"SUCCESS", "FAILURE", "DELAY", "SUCCESS,FAILURE", "SUCCESS,FAILURE,DELAY", "NEVER"
|
||||
]
|
||||
email_account_name: DF.Data | None
|
||||
email_id: DF.Data
|
||||
email_server: DF.Data | None
|
||||
|
|
@ -220,7 +223,8 @@ class EmailAccount(Document):
|
|||
frappe.throw(_("SMTP Server is required"))
|
||||
|
||||
self.flags.validate_smtp_connection = True
|
||||
self.get_smtp_server().session
|
||||
session = self.get_smtp_server().session
|
||||
self.validate_dsn(session)
|
||||
del self._smtp_server_instance
|
||||
|
||||
def validate_reply_to_addresses(self) -> None:
|
||||
|
|
@ -229,6 +233,18 @@ class EmailAccount(Document):
|
|||
frappe.throw(_("Reply To email is required"))
|
||||
validate_email_address(reply_to.email, True)
|
||||
|
||||
def validate_dsn(self, smtp_session) -> None:
|
||||
"""Validate if the configured SMTP server supports DSN (Delivery Status Notification)."""
|
||||
|
||||
if not self.dsn_notify_type:
|
||||
return
|
||||
|
||||
if not smtp_session.has_extn("DSN"):
|
||||
self.dsn_notify_type = None
|
||||
frappe.msgprint(
|
||||
_("The configured SMTP server does not support DSN (Delivery Status Notification).")
|
||||
)
|
||||
|
||||
def before_save(self):
|
||||
messages = []
|
||||
as_list = 1
|
||||
|
|
|
|||
|
|
@ -196,10 +196,20 @@ class EmailQueue(Document):
|
|||
is_newsletter=is_newsletter,
|
||||
)
|
||||
else:
|
||||
mail_options = []
|
||||
rcpt_options = []
|
||||
|
||||
if ctx.smtp_server.session.has_extn("DSN"):
|
||||
if dsn_notify_type := ctx.email_account_doc.dsn_notify_type:
|
||||
mail_options = ["RET=FULL", f"ENVID={self.name}"]
|
||||
rcpt_options = [f"NOTIFY={dsn_notify_type}"]
|
||||
|
||||
ctx.smtp_server.session.sendmail(
|
||||
from_addr=self.sender,
|
||||
to_addrs=recipient.recipient,
|
||||
msg=message.decode("utf-8").encode(),
|
||||
mail_options=mail_options,
|
||||
rcpt_options=rcpt_options,
|
||||
)
|
||||
|
||||
ctx.update_recipient_status_to_sent(recipient)
|
||||
|
|
|
|||
|
|
@ -92,6 +92,9 @@ class SMTPServer:
|
|||
if res[0] != 235:
|
||||
frappe.msgprint(res[1], raise_exception=frappe.OutgoingEmailError)
|
||||
|
||||
# Re-issue EHLO after AUTH to refresh server capabilities
|
||||
_session.ehlo()
|
||||
|
||||
self._session = _session
|
||||
self._enqueue_connection_closure()
|
||||
return self._session
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue