diff options
| author | Julien Castiaux <juc@odoo.com> | 2019-11-19 08:49:53 +0000 |
|---|---|---|
| committer | Julien Castiaux <juc@odoo.com> | 2020-05-05 09:17:15 +0000 |
| commit | afcb7349083c669dbda18b9b1955eabbe14ea675 (patch) | |
| tree | 68d71ea2dd42405e3e1242d1150e62c74493f9c1 /odoo/tools/mail.py | |
| parent | 89c1d81b24ad64e7eca6803dd4e5e6e21025ae17 (diff) | |
[IMP] ir_mail_server: IDNA and SMTPUTF8 capabilities
It has been a recurrent request from customers to be able to send email
messages to email addresses containing non-ascii characters. [IDNA] is a
domain extension to allow unicode characters in domain names. [SMTPUTF8]
is a SMTP extension to allow unicode in any header.
IDNA defines the [punycode] encoding which translates unicode to an
ascii representation. This encoding MUST be used to encode domains.
SMTPUTF8 is an SMTP extension that allow utf-8 in all headers on the
envelope.
[IDNA] https://tools.ietf.org/html/rfc5890
[SMTPUTF8] https://tools.ietf.org/html/rfc6531
[punycode] https://tools.ietf.org/html/rfc3492
Task: 2116928
opw-2229906
opw-2248251
closes odoo/odoo#47709
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
Diffstat (limited to 'odoo/tools/mail.py')
| -rw-r--r-- | odoo/tools/mail.py | 32 |
1 files changed, 20 insertions, 12 deletions
diff --git a/odoo/tools/mail.py b/odoo/tools/mail.py index c1a14e964fc..1a3e9d80b9f 100644 --- a/odoo/tools/mail.py +++ b/odoo/tools/mail.py @@ -14,6 +14,7 @@ import time from email.utils import getaddresses from lxml import etree from werkzeug import urls +import idna import odoo from odoo.loglevels import ustr @@ -546,13 +547,15 @@ def decode_message_header(message, header, separator=' '): 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. - If the first element of pair is falsy then only the email address is returned. + Set the charset to ascii to get a RFC-2822 compliant email. The + realname will be base64 encoded (if necessary) and the domain part + of the email will be punycode encoded (if necessary). The local part + is left unchanged thus require the SMTPUTF8 extension when there are + non-ascii characters. + >>> formataddr(('John Doe', 'johndoe@example.com')) '"John Doe" <johndoe@example.com>' @@ -560,21 +563,26 @@ def formataddr(pair, charset='utf-8'): 'johndoe@example.com' """ name, address = pair - address.encode('ascii') + local, _, domain = address.rpartition('@') + + try: + domain.encode(charset) + except UnicodeEncodeError: + # rfc5890 - Internationalized Domain Names for Applications (IDNA) + domain = idna.encode(domain).decode('ascii') + if name: try: name.encode(charset) except UnicodeEncodeError: # 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'), - addr=address) + name = base64.b64encode(name.encode('utf-8')).decode('ascii') + return f"=?utf-8?b?{name}?= <{local}@{domain}>" else: # ascii name, escape it if needed # rfc2822 - Internet Message Format # #section-3.4 - Address Specification - return '"{name}" <{addr}>'.format( - name=email_addr_escapes_re.sub(r'\\\g<0>', name), - addr=address) - return address + name = email_addr_escapes_re.sub(r'\\\g<0>', name) + return f'"{name}" <{local}@{domain}>' + return f"{local}@{domain}" |
