From ff39b6ae5f6024bb5ab3118d7b4171a0cb539678 Mon Sep 17 00:00:00 2001 From: "Chinmay D. Pai" Date: Fri, 17 Jul 2020 16:24:31 +0530 Subject: [PATCH 1/9] fix: email encoding issue inside email queue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit email addresses get formatted incorrectly inside the email queue, causing emails to be sent with encoded-words addresses instead of proper, human readable email addresses. this particularly happens when the address has special and accented characters. an example of encoded-words address looks like: =?utf-8?q?=C3=A1dministr=C3=A1tor?= instead of something like: ádministrátor another issue that causes this is validations that strip html tags from field when ignore_xss_filter is not set in a docfield. setting ignore_xss_filter for the email field inside email queue fixes this issue. Signed-off-by: Chinmay D. Pai --- frappe/core/doctype/communication/email.py | 2 +- .../doctype/email_queue/email_queue.json | 564 ++---------------- frappe/utils/__init__.py | 5 +- 3 files changed, 49 insertions(+), 522 deletions(-) diff --git a/frappe/core/doctype/communication/email.py b/frappe/core/doctype/communication/email.py index e9db865ade..4c531fbac6 100755 --- a/frappe/core/doctype/communication/email.py +++ b/frappe/core/doctype/communication/email.py @@ -236,7 +236,7 @@ def prepare_to_notify(doc, print_html=None, print_format=None, attachments=None) if doc.sender: # combine for sending to get the format 'Jane ' - doc.sender = formataddr([doc.sender_full_name, doc.sender]) + doc.sender = get_formatted_email(doc.sender_full_name, mail=doc.sender) doc.attachments = [] diff --git a/frappe/email/doctype/email_queue/email_queue.json b/frappe/email/doctype/email_queue/email_queue.json index ee8683af22..4529ea8211 100644 --- a/frappe/email/doctype/email_queue/email_queue.json +++ b/frappe/email/doctype/email_queue/email_queue.json @@ -1,640 +1,166 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, + "actions": [], "autoname": "hash", - "beta": 0, "creation": "2012-08-02 15:17:28", - "custom": 0, "description": "Email Queue records.", - "docstatus": 0, "doctype": "DocType", "document_type": "System", - "editable_grid": 0, "engine": "InnoDB", + "field_order": [ + "sender", + "recipients", + "show_as_cc", + "message", + "status", + "error", + "message_id", + "reference_doctype", + "reference_name", + "communication", + "send_after", + "priority", + "add_unsubscribe_link", + "unsubscribe_param", + "unsubscribe_method", + "expose_recipients", + "attachments", + "retry" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "sender", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, + "ignore_xss_filter": 1, "label": "Sender", - "length": 0, - "no_copy": 0, - "options": "Email", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "Email" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "recipients", "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Recipient", - "length": 0, - "no_copy": 0, - "options": "Email Queue Recipient", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "Email Queue Recipient" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "show_as_cc", "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Show as cc", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Show as cc" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "message", "fieldtype": "Code", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Message", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Message" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "Not Sent", "fieldname": "status", "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, "in_standard_filter": 1, "label": "Status", - "length": 0, - "no_copy": 0, - "options": "\nNot Sent\nSending\nSent\nError\nExpired", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "\nNot Sent\nSending\nSent\nError\nExpired" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "error", "fieldtype": "Code", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Error", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Error" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "message_id", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Message ID", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "reference_doctype", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Reference Document Type", - "length": 0, - "no_copy": 0, "options": "DocType", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "reference_name", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Reference DocName", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "communication", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Communication", - "length": 0, - "no_copy": 0, "options": "Communication", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "send_after", "fieldtype": "Datetime", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Send After", - "length": 0, "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "1", "fieldname": "priority", "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Priority", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "1", "fieldname": "add_unsubscribe_link", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Add Unsubscribe Link", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Add Unsubscribe Link" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "unsubscribe_param", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Unsubscribe Param", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "unsubscribe_method", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Unsubscribe Method", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Unsubscribe Method" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "expose_recipients", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Expose Recipients", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Expose Recipients" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "attachments", "fieldtype": "Code", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Attachments", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "0", "fieldname": "retry", "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Retry", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 + "read_only": 1 } ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, "icon": "fa fa-envelope", "idx": 1, - "image_view": 0, "in_create": 1, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2019-09-05 14:22:27.664645", + "links": [], + "modified": "2020-07-17 15:58:15.369419", "modified_by": "Administrator", "module": "Email", "name": "Email Queue", "owner": "Administrator", "permissions": [ { - "amend": 0, - "cancel": 0, - "create": 0, "delete": 1, "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, "print": 1, "read": 1, "report": 1, - "role": "System Manager", - "set_user_permissions": 0, - "share": 0, - "submit": 0, - "write": 0 + "role": "System Manager" } ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, + "sort_field": "modified", "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0, - "track_views": 0 + "track_changes": 1 } \ No newline at end of file diff --git a/frappe/utils/__init__.py b/frappe/utils/__init__.py index f996b5109e..1da220dc30 100644 --- a/frappe/utils/__init__.py +++ b/frappe/utils/__init__.py @@ -63,10 +63,11 @@ def get_email_address(user=None): return frappe.db.get_value("User", user, "email") -def get_formatted_email(user): +def get_formatted_email(user, mail=None): """get Email Address of user formatted as: `John Doe `""" fullname = get_fullname(user) - mail = get_email_address(user) + if not mail: + mail = get_email_address(user) return cstr(make_header(decode_header(formataddr((fullname, mail))))) def extract_email_id(email): From 39ec64f1e3ba69f2b83c09afbceee31760950b93 Mon Sep 17 00:00:00 2001 From: "Chinmay D. Pai" Date: Fri, 17 Jul 2020 18:36:53 +0530 Subject: [PATCH 2/9] fix: add default email policy to mail body the default policy encodes special characters correctly, and is not set by _default_ unless python3.8 is used. so we'll explicitly define the policy to be used for the email body Signed-off-by: Chinmay D. Pai --- frappe/email/email_body.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frappe/email/email_body.py b/frappe/email/email_body.py index 8340d81917..d21d9290fb 100755 --- a/frappe/email/email_body.py +++ b/frappe/email/email_body.py @@ -11,6 +11,7 @@ import email.utils from six import iteritems, text_type, string_types from email.mime.multipart import MIMEMultipart from email.header import Header +from email import policy def get_email(recipients, sender='', msg='', subject='[No Subject]', @@ -68,7 +69,7 @@ class EMail: self.subject = subject self.expose_recipients = expose_recipients - self.msg_root = MIMEMultipart('mixed') + self.msg_root = MIMEMultipart('mixed', policy=policy.default) self.msg_alternative = MIMEMultipart('alternative') self.msg_root.attach(self.msg_alternative) self.cc = cc or [] @@ -238,7 +239,7 @@ class EMail: """validate, build message and convert to string""" self.validate() self.make() - return self.msg_root.as_string() + return self.msg_root.as_string(policy=policy.default) def get_formatted_html(subject, message, footer=None, print_html=None, email_account=None, header=None, unsubscribe_link=None, sender=None): From 3678435d4ab3e0c706bbc5c9a7b6bb3e7f46d789 Mon Sep 17 00:00:00 2001 From: "Chinmay D. Pai" Date: Fri, 17 Jul 2020 18:38:57 +0530 Subject: [PATCH 3/9] fix: remove redundant condition for field sanitization Signed-off-by: Chinmay D. Pai --- frappe/model/base_document.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index c7ef7890b4..d89800b296 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -702,10 +702,7 @@ class BaseDocument(object): df = self.meta.get_field(fieldname) sanitized_value = value - if df and df.get("fieldtype") in ("Data", "Code", "Small Text", "Text") and df.get("options")=="Email": - sanitized_value = sanitize_email(value) - - elif df and (df.get("ignore_xss_filter") + if df and (df.get("ignore_xss_filter") or (df.get("fieldtype")=="Code" and df.get("options")!="Email") or df.get("fieldtype") in ("Attach", "Attach Image", "Barcode") From cac8a8c4a0ab67b83f665905fab6a10c316bc70f Mon Sep 17 00:00:00 2001 From: prssanna Date: Sat, 18 Jul 2020 14:16:16 +0530 Subject: [PATCH 4/9] fix: set policy to SMTPUTF8 --- frappe/email/email_body.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/email/email_body.py b/frappe/email/email_body.py index d21d9290fb..a004bbac5f 100755 --- a/frappe/email/email_body.py +++ b/frappe/email/email_body.py @@ -239,7 +239,7 @@ class EMail: """validate, build message and convert to string""" self.validate() self.make() - return self.msg_root.as_string(policy=policy.default) + return self.msg_root.as_string(policy=policy.SMTPUTF8) def get_formatted_html(subject, message, footer=None, print_html=None, email_account=None, header=None, unsubscribe_link=None, sender=None): From 742d79cd5fd0d4d44ecff987a29b1d70ab124798 Mon Sep 17 00:00:00 2001 From: prssanna Date: Sat, 18 Jul 2020 14:16:32 +0530 Subject: [PATCH 5/9] style: fix indent --- frappe/model/base_document.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index d89800b296..7d56736cdc 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -703,12 +703,12 @@ class BaseDocument(object): sanitized_value = value if df and (df.get("ignore_xss_filter") - or (df.get("fieldtype")=="Code" and df.get("options")!="Email") - or df.get("fieldtype") in ("Attach", "Attach Image", "Barcode") + or (df.get("fieldtype")=="Code" and df.get("options")!="Email") + or df.get("fieldtype") in ("Attach", "Attach Image", "Barcode") - # cancelled and submit but not update after submit should be ignored - or self.docstatus==2 - or (self.docstatus==1 and not df.get("allow_on_submit"))): + # cancelled and submit but not update after submit should be ignored + or self.docstatus==2 + or (self.docstatus==1 and not df.get("allow_on_submit"))): continue else: From c45864eac0a4049b58ed826a86b6c5651990c61f Mon Sep 17 00:00:00 2001 From: "Chinmay D. Pai" Date: Sat, 18 Jul 2020 18:27:44 +0530 Subject: [PATCH 6/9] fix: specify SMTPUTF8 policy everywhere Signed-off-by: Chinmay D. Pai --- frappe/email/email_body.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/frappe/email/email_body.py b/frappe/email/email_body.py index a004bbac5f..a404f7fdfa 100755 --- a/frappe/email/email_body.py +++ b/frappe/email/email_body.py @@ -69,8 +69,8 @@ class EMail: self.subject = subject self.expose_recipients = expose_recipients - self.msg_root = MIMEMultipart('mixed', policy=policy.default) - self.msg_alternative = MIMEMultipart('alternative') + self.msg_root = MIMEMultipart('mixed', policy=policy.SMTPUTF8) + self.msg_alternative = MIMEMultipart('alternative', policy=policy.SMTPUTF8) self.msg_root.attach(self.msg_alternative) self.cc = cc or [] self.bcc = bcc or [] @@ -101,7 +101,7 @@ class EMail: Attach message in the text portion of multipart/alternative """ from email.mime.text import MIMEText - part = MIMEText(message, 'plain', 'utf-8') + part = MIMEText(message, 'plain', 'utf-8', policy=policy.SMTPUTF8) self.msg_alternative.attach(part) def set_part_html(self, message, inline_images): @@ -114,9 +114,9 @@ class EMail: message, _inline_images = replace_filename_with_cid(message) # prepare parts - msg_related = MIMEMultipart('related') + msg_related = MIMEMultipart('related', policy=policy.SMTPUTF8) - html_part = MIMEText(message, 'html', 'utf-8') + html_part = MIMEText(message, 'html', 'utf-8', policy=policy.SMTPUTF8) msg_related.attach(html_part) for image in _inline_images: @@ -125,7 +125,7 @@ class EMail: self.msg_alternative.attach(msg_related) else: - self.msg_alternative.attach(MIMEText(message, 'html', 'utf-8')) + self.msg_alternative.attach(MIMEText(message, 'html', 'utf-8', policy=policy.SMTPUTF8)) def set_html_as_text(self, html): """Set plain text from HTML""" @@ -136,7 +136,7 @@ class EMail: from email.mime.text import MIMEText maintype, subtype = mime_type.split('/') - part = MIMEText(message, _subtype = subtype) + part = MIMEText(message, _subtype = subtype, policy=policy.SMTPUTF8) if as_attachment: part.add_header('Content-Disposition', 'attachment', filename=filename) From 8a6cb7db3d99dc55c149bf49446b612771b46f64 Mon Sep 17 00:00:00 2001 From: "Chinmay D. Pai" Date: Sat, 18 Jul 2020 18:52:55 +0530 Subject: [PATCH 7/9] chore: replace rfc-compatible newlines with \n Signed-off-by: Chinmay D. Pai --- frappe/email/test_email_body.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/email/test_email_body.py b/frappe/email/test_email_body.py index 43c4bb8333..7d24ea9025 100644 --- a/frappe/email/test_email_body.py +++ b/frappe/email/test_email_body.py @@ -39,7 +39,7 @@ This is the text version of this email subject='Test Subject', content=email_html, text_content=email_text - ).as_string() + ).as_string().replace("\r\n", "\n") def test_prepare_message_returns_already_encoded_string(self): From 42591f2828013e00e03796e2e08cc0bd98072ff1 Mon Sep 17 00:00:00 2001 From: "Chinmay D. Pai" Date: Sat, 18 Jul 2020 19:08:29 +0530 Subject: [PATCH 8/9] chore: replace rfc-compatible newline with \n Signed-off-by: Chinmay D. Pai --- frappe/email/test_email_body.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/email/test_email_body.py b/frappe/email/test_email_body.py index 7d24ea9025..705a853bc6 100644 --- a/frappe/email/test_email_body.py +++ b/frappe/email/test_email_body.py @@ -153,7 +153,7 @@ w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> subject='Test Subject', content=email_html, header=['Email Title', 'green'] - ).as_string() + ).as_string().replace("\r\n", "\n") self.assertTrue(''' Date: Sat, 18 Jul 2020 19:40:10 +0530 Subject: [PATCH 9/9] fix: don't set header if empty --- frappe/email/email_body.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frappe/email/email_body.py b/frappe/email/email_body.py index a404f7fdfa..d545190c47 100755 --- a/frappe/email/email_body.py +++ b/frappe/email/email_body.py @@ -223,7 +223,8 @@ class EMail: # reset headers as values may be changed. for key, val in iteritems(headers): - self.set_header(key, val) + if val: + self.set_header(key, val) # call hook to enable apps to modify msg_root before sending for hook in frappe.get_hooks("make_email_body_message"):