[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.MIMEText import MIMEText
from email.MIMEBase import MIMEBase from email.MIMEBase import MIMEBase
from email.MIMEMultipart import MIMEMultipart from email.MIMEMultipart import MIMEMultipart
from email.Charset import Charset
from email.Header import Header from email.Header import Header
from email.Utils import formatdate, make_msgid, COMMASPACE from email.Utils import formatdate, make_msgid, COMMASPACE
from email import Encoders from email import Encoders
@ -97,6 +98,26 @@ def encode_header(header_text):
return header_text_ascii if header_text_ascii\ return header_text_ascii if header_text_ascii\
else Header(header_text_utf8, 'utf-8') 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*<([^ ,<@]+@[^> ,]+)>') name_with_email_pattern = re.compile(r'("[^<@>]+")\s*<([^ ,<@]+@[^> ,]+)>')
address_pattern = re.compile(r'([^ ,<@]+@[^> ,]+)') address_pattern = re.compile(r'([^ ,<@]+@[^> ,]+)')
@ -334,14 +355,16 @@ class ir_mail_server(osv.osv):
if attachments: if attachments:
for (fname, fcontent) in attachments: for (fname, fcontent) in attachments:
filename_utf8 = ustr(fname).encode('utf-8') filename_rfc2047 = encode_header_param(fname)
part = MIMEBase('application', "octet-stream") 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) part.set_payload(fcontent)
Encoders.encode_base64(part) 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) msg.attach(part)
return msg return msg