ef send_email_smtp(
to,
subject,
html_content,
config,
files=None,
data=None,
images=None,
dryrun=False,
cc=None,
bcc=None,
mime_subtype="mixed",
):
"""
Send an email with html content, eg:
send_email_smtp(
'[email protected]', 'foo', 'Foo bar',['/dev/null'], dryrun=True)
"""
smtp_mail_from = config["SMTP_MAIL_FROM"]
to = get_email_address_list(to)
msg = MIMEMultipart(mime_subtype)
msg["Subject"] = subject
msg["From"] = smtp_mail_from
msg["To"] = ", ".join(to)
msg.preamble = "This is a multi-part message in MIME format."
recipients = to
if cc:
cc = get_email_address_list(cc)
msg["CC"] = ", ".join(cc)
recipients = recipients + cc
if bcc:
# don't add bcc in header
bcc = get_email_address_list(bcc)
recipients = recipients + bcc
msg["Date"] = formatdate(localtime=True)
mime_text = MIMEText(html_content, "html")
msg.attach(mime_text)
# Attach files by reading them from disk
for fname in files or []:
basename = os.path.basename(fname)
with open(fname, "rb") as f:
msg.attach(
MIMEApplication(
f.read(),
Content_Disposition="attachment; filename='%s'" % make_header([(basename, 'UTF-8')]).encode(
'UTF-8'),
Name=make_header([(basename, 'UTF-8')]).encode('UTF-8'),
)
)
# # msg.add_header('Content-Disposition', 'attachment',
# # filename='=?utf-8?b?' + base64.b64encode(basename.encode('UTF-8')).decode() + '?=')
# msg.attach(
# MIMEApplication(
# f.read(),
# Content_Disposition="attachment; filename='%s'" % dd_b64(basename),
# Name=basename,
# )
# )
# Attach any files passed directly
for name, body in (data or {}).items():
msg.attach(
MIMEApplication(
body,
Content_Disposition="attachment; filename='%s'" % make_header([(name, 'UTF-8')]).encode('UTF-8'),
Name=make_header([(name, 'UTF-8')]).encode('UTF-8')
)
)
# # msg.add_header('Content-Disposition', 'attachment',
# # filename='=?utf-8?b?' + base64.b64encode(name.encode('UTF-8')) + '?=')
# msg.attach(
# MIMEApplication(
# body,
# Content_Disposition="attachment; filename='%s'" % dd_b64(name),
# Name=name
# )
# )
# Attach any inline images, which may be required for display in
# HTML content (inline)
for msgid, body in (images or {}).items():
image = MIMEImage(body)
image.add_header("Content-ID", "<%s>" % msgid)
image.add_header("Content-Disposition", "inline")
msg.attach(image)
send_MIME_email(smtp_mail_from, recipients, msg, config, dryrun=dryrun)
上面为修改后的代码,主要的修改是在邮件头部的设置。
第一次修改,只改了Content_Disposition 里面的filename,如下图片的修改,该修改结果是 foxmail的显示正常,但是iso 和网页版 和网易邮箱都是无法正确显示附件名称,
第二次修改,头部的name也用头部make_header 处理,如下图,无论是网页版,还是Foxmail,还是iso 还是lookout都可以正常显示:
修改后的最终代码:
msg.attach(
MIMEApplication(
f.read(),
Content_Disposition="attachment; filename='%s'" % make_header([(basename, 'UTF-8')]).encode(
'UTF-8'),
Name=make_header([(basename, 'UTF-8')]).encode('UTF-8'),
)
)
涉及到的修改还有一处:
msg.attach(
MIMEApplication(
body,
Content_Disposition="attachment; filename='%s'" % make_header([(name, 'UTF-8')]).encode('UTF-8'),
Name=make_header([(name, 'UTF-8')]).encode('UTF-8')
)
)
原理讲解:
MIMEApplication:会把默认指定传输做base64 加密Content-Transfer-Encoding: base64,因此传送时需要对数据做based64
make_header 默认会做base64
客户端在解析的时候会对其解码,如果不对内容进行base64,客户端无法解析
filename 和 Name 两者要一致