From 972a0a4557498aee10ab117ce63ea80da65ce36b Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Fri, 16 Mar 2012 14:08:03 +0100 Subject: [PATCH] [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 --- openerp/addons/base/ir/ir_mail_server.py | 33 ++++++++++++++++++++---- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/openerp/addons/base/ir/ir_mail_server.py b/openerp/addons/base/ir/ir_mail_server.py index ecb41b32592..4455cb47314 100644 --- a/openerp/addons/base/ir/ir_mail_server.py +++ b/openerp/addons/base/ir/ir_mail_server.py @@ -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