feat: addes x-priority option to email header and the frappe.sendmail function (#31966)

creating the option to give the email an importance.
1 = Highest, 3 = Normal, 5 = Lowest
commonly used to flag the importance of emails

Co-authored-by: Jan Lukas Liesen <=>
This commit is contained in:
jll-02 2025-04-11 12:48:19 +02:00 committed by GitHub
parent 34e1d58973
commit 89ed7c90a7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 34 additions and 2 deletions

View file

@ -507,6 +507,7 @@ def sendmail(
print_letterhead=False,
with_container=False,
email_read_tracker_url=None,
x_priority: Literal[1, 3, 5] = 3,
) -> Optional["EmailQueue"]:
"""Send email using user's default **Email Account** or global default **Email Account**.
@ -534,6 +535,7 @@ def sendmail(
:param args: Arguments for rendering the template
:param header: Append header in email
:param with_container: Wraps email inside a styled container
:param x_priority: 1 = HIGHEST, 3 = NORMAL, 5 = LOWEST
"""
if recipients is None:
@ -589,6 +591,7 @@ def sendmail(
print_letterhead=print_letterhead,
with_container=with_container,
email_read_tracker_url=email_read_tracker_url,
x_priority=x_priority,
)
# build email queue and send the email if send_now is True.

View file

@ -1,12 +1,15 @@
# Copyright (c) 2015, Frappe Technologies and contributors
# License: MIT. See LICENSE
from __future__ import annotations
import json
import quopri
import traceback
from contextlib import suppress
from email.parser import Parser
from email.policy import SMTP
from typing import TYPE_CHECKING
import frappe
from frappe import _, safe_encode, task
@ -34,6 +37,9 @@ from frappe.utils import (
)
from frappe.utils.verified_command import get_signed_params
if TYPE_CHECKING:
from typing import Literal
class EmailQueue(Document):
# begin: auto-generated types
@ -88,7 +94,7 @@ class EmailQueue(Document):
return duplicate
@classmethod
def new(cls, doc_data, ignore_permissions=False) -> "EmailQueue":
def new(cls, doc_data, ignore_permissions=False) -> EmailQueue:
data = doc_data.copy()
if not data.get("recipients"):
return
@ -104,7 +110,7 @@ class EmailQueue(Document):
return doc
@classmethod
def find(cls, name) -> "EmailQueue":
def find(cls, name) -> EmailQueue:
return frappe.get_doc(cls.DOCTYPE, name)
@classmethod
@ -502,6 +508,7 @@ class QueueBuilder:
print_letterhead=False,
with_container=False,
email_read_tracker_url=None,
x_priority: Literal[1, 3, 5] = 3,
):
"""Add email to sending queue (Email Queue)
@ -527,6 +534,7 @@ class QueueBuilder:
:param header: Append header in email (boolean)
:param with_container: Wraps email inside styled container
:param email_read_tracker_url: A URL for tracking whether an email is read by the recipient.
:param x_priority: 1 = HIGHEST, 3 = NORMAL, 5 = LOWEST
"""
self._unsubscribe_method = unsubscribe_method
@ -537,6 +545,7 @@ class QueueBuilder:
self._sender = sender
self._text_content = text_content
self._message = message
self._x_priority: Literal[1, 3, 5] = x_priority
self._add_unsubscribe_link = add_unsubscribe_link
self._unsubscribe_message = unsubscribe_message
self._attachments = attachments
@ -710,6 +719,7 @@ class QueueBuilder:
expose_recipients=self.expose_recipients,
inline_images=self.inline_images,
header=self.header,
x_priority=self._x_priority,
)
mail.set_message_id(self.message_id, self.is_notification)

View file

@ -1,11 +1,15 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: MIT. See LICENSE
from __future__ import annotations
import email.utils
import os
import re
from email import policy
from email.header import Header
from email.mime.multipart import MIMEMultipart
from typing import TYPE_CHECKING
import frappe
from frappe.email.doctype.email_account.email_account import EmailAccount
@ -23,6 +27,9 @@ from frappe.utils import (
)
from frappe.utils.pdf import get_pdf
if TYPE_CHECKING:
from typing import Literal
EMBED_PATTERN = re.compile("""embed=["'](.*?)["']""")
@ -44,6 +51,7 @@ def get_email(
expose_recipients=None,
inline_images=None,
header=None,
x_priority: Literal[1, 3, 5] = 3,
):
"""Prepare an email with the following format:
- multipart/mixed
@ -72,6 +80,7 @@ def get_email(
bcc=bcc,
email_account=email_account,
expose_recipients=expose_recipients,
x_priority=x_priority,
)
if not content.strip().startswith("<"):
@ -117,6 +126,7 @@ class EMail:
bcc=(),
email_account=None,
expose_recipients=None,
x_priority: Literal[1, 3, 5] = 3,
):
from email import charset as Charset
@ -142,6 +152,8 @@ class EMail:
self.bcc = bcc or []
self.html_set = False
self.x_priority: Literal[1, 3, 5] = x_priority
self.email_account = email_account or EmailAccount.find_outgoing(
match_by_email=sender, _raise_error=True
)
@ -315,6 +327,13 @@ class EMail:
"X-Frappe-Site": get_url(),
}
if self.x_priority != 3:
headers.update(
{
"X-Priority": str(self.x_priority),
}
)
# reset headers as values may be changed.
for key, val in headers.items():
if val: