refactor: read email body with policy=SMTP

`policy=SMTPUTF8` seems to break without specifying SMTPUTF8 in mail_options when actually sending the mail
(can't validate this because no server I tried seems to support that)

The `default` or `SMTP` policy work fine. Stuck to `SMTP` for CRLF line endings - default only does LF

Can get away with just changing this for SendMailContext().get_message_object(), but seemed better to standardize it

Non ASCII characters in the subject break completely, for example hindi characters get replaced by `?`

Signed-off-by: Akhil Narang <me@akhilnarang.dev>
This commit is contained in:
Akhil Narang 2024-01-10 12:47:42 +05:30
parent 55088ce7bd
commit 1147c8bbed
No known key found for this signature in database
GPG key ID: 9DCC61E211BF645F
2 changed files with 11 additions and 11 deletions

View file

@ -6,7 +6,7 @@ import quopri
import traceback
from contextlib import suppress
from email.parser import Parser
from email.policy import SMTPUTF8, default
from email.policy import SMTP
import frappe
from frappe import _, safe_encode, task
@ -266,7 +266,7 @@ class SendMailContext:
@savepoint(catch=Exception)
def notify_failed_email(self):
# Parse the email body to extract the subject
subject = Parser(policy=default).parsestr(self.queue_doc.message)["Subject"]
subject = Parser(policy=SMTP).parsestr(self.queue_doc.message)["Subject"]
# Construct the notification
notification = frappe.new_doc("Notification Log")
@ -283,7 +283,7 @@ class SendMailContext:
recipient.update_db(status="Sent", commit=True)
def get_message_object(self, message):
return Parser(policy=SMTPUTF8).parsestr(message)
return Parser(policy=SMTP).parsestr(message)
def message_placeholder(self, placeholder_key):
# sourcery skip: avoid-builtin-shadow

View file

@ -135,8 +135,8 @@ class EMail:
self.subject = subject
self.expose_recipients = expose_recipients
self.msg_root = MIMEMultipart("mixed", policy=policy.SMTPUTF8)
self.msg_alternative = MIMEMultipart("alternative", policy=policy.SMTPUTF8)
self.msg_root = MIMEMultipart("mixed", policy=policy.SMTP)
self.msg_alternative = MIMEMultipart("alternative", policy=policy.SMTP)
self.msg_root.attach(self.msg_alternative)
self.cc = cc or []
self.bcc = bcc or []
@ -185,7 +185,7 @@ class EMail:
"""
from email.mime.text import MIMEText
part = MIMEText(message, "plain", "utf-8", policy=policy.SMTPUTF8)
part = MIMEText(message, "plain", "utf-8", policy=policy.SMTP)
self.msg_alternative.attach(part)
def set_part_html(self, message, inline_images):
@ -198,9 +198,9 @@ class EMail:
message, _inline_images = replace_filename_with_cid(message)
# prepare parts
msg_related = MIMEMultipart("related", policy=policy.SMTPUTF8)
msg_related = MIMEMultipart("related", policy=policy.SMTP)
html_part = MIMEText(message, "html", "utf-8", policy=policy.SMTPUTF8)
html_part = MIMEText(message, "html", "utf-8", policy=policy.SMTP)
msg_related.attach(html_part)
for image in _inline_images:
@ -214,7 +214,7 @@ class EMail:
self.msg_alternative.attach(msg_related)
else:
self.msg_alternative.attach(MIMEText(message, "html", "utf-8", policy=policy.SMTPUTF8))
self.msg_alternative.attach(MIMEText(message, "html", "utf-8", policy=policy.SMTP))
def set_html_as_text(self, html):
"""Set plain text from HTML"""
@ -227,7 +227,7 @@ class EMail:
from email.mime.text import MIMEText
maintype, subtype = mime_type.split("/")
part = MIMEText(message, _subtype=subtype, policy=policy.SMTPUTF8)
part = MIMEText(message, _subtype=subtype, policy=policy.SMTP)
if as_attachment:
part.add_header("Content-Disposition", "attachment", filename=filename)
@ -341,7 +341,7 @@ class EMail:
"""validate, build message and convert to string"""
self.validate()
self.make()
return self.msg_root.as_string(policy=policy.SMTPUTF8)
return self.msg_root.as_string(policy=policy.SMTP)
def get_formatted_html(