[FIX] ir_mail_server: make attachment filename work properly on GMail

The default Python encoding for mail header parameters
is RFC2231, which produces headers of the form:
  Content-Disposition: attachment; filename*="utf-8abcd%C3%A9.pdf"
This works fine for e.g. Thunderbird but on GMail
such headers appear as `noname`.
We are therefore falling back to RFC2047 encoding
which will instead give something like:
  Content-Disposition: attachment; filename="=?utf-8?b?UmVxdWVzdCf?="

bzr revid: odo@openerp.com-20120316130803-zo4fwuk7h6bq6k54
This commit is contained in:
Olivier Dony 2012-03-16 14:08:03 +01:00
parent b37d72428b
commit 972a0a4557
1 changed files with 28 additions and 5 deletions

View File

@ -22,6 +22,7 @@
from email.MIMEText import MIMEText
from email.MIMEBase import MIMEBase
from email.MIMEMultipart import MIMEMultipart
from email.Charset import Charset
from email.Header import Header
from email.Utils import formatdate, make_msgid, COMMASPACE
from email import Encoders
@ -97,6 +98,26 @@ def encode_header(header_text):
return header_text_ascii if header_text_ascii\
else Header(header_text_utf8, 'utf-8')
def encode_header_param(param_text):
"""Returns an appropriate RFC2047 encoded representation of the given
header parameter value, suitable for direct assignation as the
param value (e.g. via Message.set_param() or Message.add_header())
RFC2822 assumes that headers contain only 7-bit characters,
so we ensure it is the case, using RFC2047 encoding when needed.
:param param_text: unicode or utf-8 encoded string with header value
:rtype: string
:return: if ``param_text`` represents a plain ASCII string,
return the same 7-bit string, otherwise returns an
ASCII string containing the RFC2047 encoded text.
"""
# For details see the encode_header() method that uses the same logic
if not param_text: return ""
param_text_utf8 = tools.ustr(param_text).encode('utf-8')
param_text_ascii = try_coerce_ascii(param_text_utf8)
return param_text_ascii if param_text_ascii\
else Charset('utf8').header_encode(param_text_utf8)
name_with_email_pattern = re.compile(r'("[^<@>]+")\s*<([^ ,<@]+@[^> ,]+)>')
address_pattern = re.compile(r'([^ ,<@]+@[^> ,]+)')
@ -334,14 +355,16 @@ class ir_mail_server(osv.osv):
if attachments:
for (fname, fcontent) in attachments:
filename_utf8 = ustr(fname).encode('utf-8')
filename_rfc2047 = encode_header_param(fname)
part = MIMEBase('application', "octet-stream")
# The default RFC2231 encoding of Message.add_header() works in Thunderbird but not GMail
# so we fix it by using RFC2047 encoding for the filename instead.
part.set_param('name', filename_rfc2047)
part.add_header('Content-Disposition', 'attachment', filename=filename_rfc2047)
part.set_payload(fcontent)
Encoders.encode_base64(part)
# Force RFC2231 encoding for attachment filename
# See email.message.Message.add_header doc
part.add_header('Content-Disposition', 'attachment',
filename=('utf-8',None,filename_utf8))
msg.attach(part)
return msg