[IMP] tools: restore P2 formataddr default behavior

Python 2 `email.tools.formataddr` doesn't encode not RFC-2822 compliant
realname to base64 or quoted-printable. This is the wanted behavior to
output formatted email addresses on screen.

Python 3 `email.tools.formataddr` does encode the realname to be
RFC-2822 compliant. This is the wanted behavior when connecting to a
smtp server to send emails.

That method has been deprecated by pep-594 as the new python email API
is capable of automatically formatting email address in a RFC compliant
way. As the method was still in use in a lot of modules as the
preferred way to format email addresses, a refined P3-like
implementation as been included in the tool suite.

This commit changes the default behavior so it mimics P2 implementation
with an easy way to use the P3 behavior.

Task: 2003936
This commit is contained in:
Julien Castiaux
2019-11-12 13:48:40 +00:00
parent f0ae04ab3d
commit 7b65a63c97
2 changed files with 32 additions and 6 deletions
+26 -1
View File
@@ -6,7 +6,10 @@ from unittest.mock import patch
from odoo.tests.common import BaseCase
from odoo.tests.common import SavepointCase
from odoo.tools import html_sanitize, append_content_to_html, plaintext2html, email_split, misc
from odoo.tools import (
html_sanitize, append_content_to_html, plaintext2html, email_split,
misc, formataddr,
)
from . import test_mail_examples
@@ -328,6 +331,28 @@ class TestEmailTools(BaseCase):
for text, expected in cases:
self.assertEqual(email_split(text), expected, 'email_split is broken')
def test_email_formataddr(self):
email = 'joe@example.com'
cases = [
# (name, address), charsets expected
(('', email), ['ascii', 'utf-8'], 'joe@example.com'),
(('joe', email), ['ascii', 'utf-8'], '"joe" <joe@example.com>'),
(('joe doe', email), ['ascii', 'utf-8'], '"joe doe" <joe@example.com>'),
(('joe"doe', email), ['ascii', 'utf-8'], '"joe\\"doe" <joe@example.com>'),
(('joé', email), ['ascii'], '=?utf-8?b?am/DqQ==?= <joe@example.com>'),
(('joé', email), ['utf-8'], '"joé" <joe@example.com>'),
(('', 'joé@example.com'), ['ascii', 'utf-8'], UnicodeEncodeError), # need SMTPUTF8 support
(('', 'joe@examplé.com'), ['ascii', 'utf-8'], UnicodeEncodeError), # need IDNA support
]
for pair, charsets, expected in cases:
for charset in charsets:
with self.subTest(pair=pair, charset=charset):
if isinstance(expected, str):
self.assertEqual(formataddr(pair, charset), expected)
else:
self.assertRaises(expected, formataddr, pair, charset)
class EmailConfigCase(SavepointCase):
@patch.dict("odoo.tools.config.options", {"email_from": "settings@example.com"})
+6 -5
View File
@@ -516,9 +516,10 @@ def email_escape_char(email_address):
def decode_message_header(message, header, separator=' '):
return separator.join(h for h in message.get_all(header, []) if h)
def formataddr(pair):
"""Takes a 2-tuple of the form (realname, email_address) and returns
the string value suitable for an RFC 2822 From, To or Cc header.
def formataddr(pair, charset='utf-8'):
"""Pretty format a 2-tuple of the form (realname, email_address).
Set the charset to ascii to get a RFC-2822 compliant email.
The email address is considered valid and is left unmodified.
@@ -535,9 +536,9 @@ def formataddr(pair):
address.encode('ascii')
if name:
try:
name.encode('ascii')
name.encode(charset)
except UnicodeEncodeError:
# non-ascii name, transcode the name in a safe format
# charset mismatch, encode as utf-8/base64
# rfc2047 - MIME Message Header Extensions for Non-ASCII Text
return "=?utf-8?b?{name}?= <{addr}>".format(
name=base64.b64encode(name.encode('utf-8')).decode('ascii'),