summaryrefslogtreecommitdiff
path: root/odoo/addons/base/ir/ir_mail_server.py
diff options
context:
space:
mode:
authorXavier Morel <xmo@odoo.com>2017-05-17 10:59:41 +0200
committerOlivier Dony <odo@openerp.com>2017-08-20 23:25:54 +0200
commit200612ca1ef1a1bf75dbe52feef5a09ae5a58ca6 (patch)
treec9243ec052649007c3c0c083b71cd290bc923f1a /odoo/addons/base/ir/ir_mail_server.py
parentae866acf08abe91fe87a3d3f4899070962b795cc (diff)
[FIX] P3: text model in various mail bits
No formal decision there, and the stdlib API seems like a PITA as it's based around native strings, not bytes and not text. * try to use cross-model API instead of random encode/decode * unicode all the mail_template things * formataddr *requires* a text tuple now In P2, formataddr((False, False)) "worked" (generated "False <False>"), in P3 it will fail and blow up. * attachments are quite definitely bytes * remove try_coerce_ascii because it's garbage
Diffstat (limited to 'odoo/addons/base/ir/ir_mail_server.py')
-rw-r--r--odoo/addons/base/ir/ir_mail_server.py75
1 files changed, 33 insertions, 42 deletions
diff --git a/odoo/addons/base/ir/ir_mail_server.py b/odoo/addons/base/ir/ir_mail_server.py
index 91cf0e61e73..eab160b4a84 100644
--- a/odoo/addons/base/ir/ir_mail_server.py
+++ b/odoo/addons/base/ir/ir_mail_server.py
@@ -39,20 +39,8 @@ class WriteToLogger(object):
_logger.debug(s)
smtplib.stderr = WriteToLogger()
-def try_coerce_ascii(string_utf8):
- """Attempts to decode the given utf8-encoded string
- as ASCII after coercing it to UTF-8, then return
- the confirmed 7-bit ASCII string.
-
- If the process fails (because the string
- contains non-ASCII characters) returns ``None``.
- """
- try:
- string_utf8.decode('ascii')
- except UnicodeDecodeError:
- return
- return string_utf8
-
+def is_ascii(s):
+ return all(ord(cp) < 128 for cp in s)
def encode_header(header_text):
"""Returns an appropriate representation of the given header value,
@@ -70,16 +58,10 @@ def encode_header(header_text):
"""
if not header_text:
return ""
- # convert anything to utf-8, suitable for testing ASCIIness, as 7-bit chars are
- # encoded as ASCII in utf-8
- header_text_utf8 = ustr(header_text).encode('utf-8')
- header_text_ascii = try_coerce_ascii(header_text_utf8)
- # if this header contains non-ASCII characters,
- # we'll need to wrap it up in a message.header.Header
- # that will take care of RFC2047-encoding it as
- # 7-bit string.
- return header_text_ascii or Header(header_text_utf8, 'utf-8')
-
+ header_text = ustr(header_text) # FIXME: require unicode higher up?
+ if is_ascii(header_text):
+ return pycompat.to_native(header_text)
+ Header(header_text, 'utf-8')
def encode_header_param(param_text):
"""Returns an appropriate RFC2047 encoded representation of the given
@@ -97,10 +79,10 @@ def encode_header_param(param_text):
# For details see the encode_header() method that uses the same logic
if not param_text:
return ""
- param_text_utf8 = ustr(param_text).encode('utf-8')
- param_text_ascii = try_coerce_ascii(param_text_utf8)
- return param_text_ascii or Charset('utf8').header_encode(param_text_utf8)
-
+ param_text = ustr(param_text) # FIXME: require unicode higher up?
+ if is_ascii(param_text):
+ return pycompat.to_native(param_text) # TODO: is that actually necessary?
+ return Charset("utf-8").header_encode(param_text)
address_pattern = re.compile(r'([^ ,<@]+@[^> ,]+)')
@@ -111,8 +93,8 @@ def extract_rfc2822_addresses(text):
"""
if not text:
return []
- candidates = address_pattern.findall(ustr(text).encode('utf-8'))
- return [c for c in candidates if try_coerce_ascii(c)]
+ candidates = address_pattern.findall(ustr(text))
+ return [c for c in candidates if is_ascii(c)]
def encode_rfc2822_address_header(header_text):
@@ -124,11 +106,20 @@ def encode_rfc2822_address_header(header_text):
"""
def encode_addr(addr):
name, email = addr
- if not try_coerce_ascii(name):
- name = str(Header(name, 'utf-8'))
+ # If s is a <text string>, then charset is a hint specifying the
+ # character set of the characters in the string. The Unicode string
+ # will be encoded using the following charsets in order: us-ascii,
+ # the charset hint, utf-8. The first character set to not provoke a
+ # UnicodeError is used.
+ # -> always pass a text string to Header
+
+ # also Header.__str__ in Python 3 "Returns an approximation of the
+ # Header as a string, using an unlimited line length.", the old one
+ # was "A synonym for Header.encode()." so call encode() directly?
+ name = Header(pycompat.to_text(name)).encode()
return formataddr((name, email))
- addresses = getaddresses([ustr(header_text).encode('utf-8')])
+ addresses = getaddresses([pycompat.to_native(ustr(header_text))])
return COMMASPACE.join(encode_addr(a) for a in addresses)
@@ -252,8 +243,8 @@ class IrMailServer(models.Model):
# The user/password must be converted to bytestrings in order to be usable for
# certain hashing schemes, like HMAC.
# See also bug #597143 and python issue #5285
- smtp_user = ustr(smtp_user).encode('utf-8')
- smtp_password = ustr(smtp_password).encode('utf-8')
+ smtp_user = pycompat.to_native(ustr(smtp_user))
+ smtp_password = pycompat.to_native(ustr(smtp_password))
connection.login(smtp_user, smtp_password)
return connection
@@ -301,8 +292,8 @@ class IrMailServer(models.Model):
email_bcc = email_bcc or []
body = body or u''
- email_body_utf8 = ustr(body).encode('utf-8')
- email_text_part = MIMEText(email_body_utf8, _subtype=subtype, _charset='utf-8')
+ email_body = ustr(body)
+ email_text_part = MIMEText(email_body, _subtype=subtype, _charset='utf-8')
msg = MIMEMultipart()
if not message_id:
@@ -328,20 +319,20 @@ class IrMailServer(models.Model):
msg['Date'] = formatdate()
# Custom headers may override normal headers or provide additional ones
for key, value in pycompat.items(headers):
- msg[ustr(key).encode('utf-8')] = encode_header(value)
+ msg[pycompat.to_native(ustr(key))] = encode_header(value)
if subtype == 'html' and not body_alternative:
# Always provide alternative text body ourselves if possible.
- text_utf8 = html2text.html2text(email_body_utf8.decode('utf-8')).encode('utf-8')
+ text = html2text.html2text(email_body_utf8)
alternative_part = MIMEMultipart(_subtype="alternative")
- alternative_part.attach(MIMEText(text_utf8, _charset='utf-8', _subtype='plain'))
+ alternative_part.attach(MIMEText(text, _charset='utf-8', _subtype='plain'))
alternative_part.attach(email_text_part)
msg.attach(alternative_part)
elif body_alternative:
# Include both alternatives, as specified, within a multipart/alternative part
alternative_part = MIMEMultipart(_subtype="alternative")
- body_alternative_utf8 = ustr(body_alternative).encode('utf-8')
- alternative_body_part = MIMEText(body_alternative_utf8, _subtype=subtype_alternative, _charset='utf-8')
+ body_alternative_ = ustr(body_alternative)
+ alternative_body_part = MIMEText(body_alternative_, _subtype=subtype_alternative, _charset='utf-8')
alternative_part.attach(alternative_body_part)
alternative_part.attach(email_text_part)
msg.attach(alternative_part)