Django EmailMultiAlternatives 和 Win2003 上 Outlook 2003 的 HTML 邮件显示
我在用django.core.mail.EmailMultiAlternatives发送邮件,这样可以确保如果邮件客户端不支持HTML格式,消息会自动降级为文本格式。
这是我的send_email方法:
def send_email(self, from_address, to_list, subject, msg_text, msg_html):
subject=subject.replace('\r','').replace('\n',' ')
self.msg = EmailMultiAlternatives(subject, msg_text, from_address, to_list)
self.msg.attach_alternative(msg_html, "text/html")
self.msg.content_subtype = "html"
self.msg.send()
在Gmail、Hotmail和很多其他邮件客户端上效果很好,HTML内容显示得没问题。但是在运行Windows 2003的Outlook 2003上,它只显示文本版本,不显示HTML内容。
如果我强制在EmailMultiAlternatives调用中放入HTML内容,也就是用msg_html
代替msg_text
,像这样:
self.msg = EmailMultiAlternatives(subject, msg_html, from_address, to_list)
那么在所有客户端上都能正常工作;但这样就意味着对于那些不支持HTML的客户端,或者更可能是那些禁用了HTML支持的客户端,就没有文本备选方案了。
我觉得值得一提的是,这封邮件是在运行Mac OS X的django应用上生成的(以防这和不同操作系统之间的换行符有关系)。
我看到其他语言的用户也遇到过类似的问题,尤其是在使用Outlook时……
我想知道有没有人知道为什么Outlook会表现得不同,以及是否有简单的解决办法可以在我的代码中应用?
1 个回答
我没有安装Outlook来测试这个,所以我想知道你函数里的第五行是干嘛的。
self.msg.content_subtype = "html"
我对多部分邮件的内部结构了解不多,但在我的系统上,那一行代码让消息的两个部分都变成了内容类型为text/html。如果不加这一行,第一部分的内容类型会是"text/plain",第二部分则是"text/html"。
无论如何,有一个关于Java的回答提到要把字符集改成iso-8859-1。我觉得你可以用django.core.mail来做到这一点。
EmailMessage类(EmailMultiAlternatives是从这个类继承的)有一个叫“encoding”的属性,可以设置要使用的字符集。默认情况下,这个属性是None,所以会使用utf-8作为默认字符集(除非在设置中另行指定)。
换句话说,在问题中提到的函数的发送行之前,加上类似下面的代码:
self.msg.content_subtype = "iso-8859-1"
不幸的是,这样做只会改变第一部分(上面函数中的msg_text)的编码。负责附加替代内容的函数似乎并没有使用这个encoding属性。我不确定这是不是正确的方法,但我通过子类化EmailMultiAlternatives来重写相关函数,结果看起来还不错。
class EmailMultiAlternativesWithEncoding(EmailMultiAlternatives):
def _create_attachment(self, filename, content, mimetype=None):
"""
Converts the filename, content, mimetype triple into a MIME attachment
object. Use self.encoding when handling text attachments.
"""
if mimetype is None:
mimetype, _ = mimetypes.guess_type(filename)
if mimetype is None:
mimetype = DEFAULT_ATTACHMENT_MIME_TYPE
basetype, subtype = mimetype.split('/', 1)
if basetype == 'text':
encoding = self.encoding or settings.DEFAULT_CHARSET
attachment = SafeMIMEText(smart_str(content,
settings.DEFAULT_CHARSET), subtype, encoding)
# original text being replaced above (not last argument)
# attachment = SafeMIMEText(smart_str(content,
# settings.DEFAULT_CHARSET), subtype, settings.DEFAULT_CHARSET)
else:
# Encode non-text attachments with base64.
attachment = MIMEBase(basetype, subtype)
attachment.set_payload(content)
Encoders.encode_base64(attachment)
if filename:
attachment.add_header('Content-Disposition', 'attachment',
filename=filename)
return attachment
我不确定“smart_str(content, settings.DEFAULT_CHARSET)”这一部分是否也应该引用“encoding”,而不是“settings.DEFAULT_CHARSET”,但这是处理消息正文文本的方式(django.core.mail.EmailMessage.message)。
正如我所说,我没有Outlook,所以无法实际测试与Outlook相关的部分,但似乎确实把两个部分的字符集都改成了iso-8859-1。