Python smtplib发送HTML/纯文本邮件异常:显示与编码问题
问题排查与解决方案
核心问题解析
- MIME多部分结构直接显示:未正确设置邮件的
multipart/alternative类型,导致邮件客户端无法识别内容版本,直接输出原始MIME源码。 - 编码显示异常:
Gr=C3=BCsse是UTF-8内容的quoted-printable编码形式,未显式指定编码或编码处理逻辑缺失,导致客户端未自动解码。 - 换行丢失问题:HTML内容的换行需要用
<br>标签或块级元素实现,纯文本换行需保留原始格式,此前未区分处理两种内容的换行规则。
修正步骤
1. 正确构建多部分邮件
使用EmailMessage时,必须将邮件的Content-Type设置为multipart/alternative,这是告诉客户端这是同一内容的不同展示版本,优先渲染HTML。
2. 显式指定编码
为纯文本和HTML部分都指定utf-8编码,确保特殊字符(如德语变音符号)被正确处理,避免编码混乱。
3. 区分处理换行
- 纯文本部分:保留原始字符串的换行符(
\n)。 - HTML部分:将原始文本中的换行符转换为
<br>标签,或确保BBcode转换后的HTML已包含正确的换行格式。
4. 使用正确的发送方法
坚持使用send_message而非sendmail,前者会自动处理MIME结构的封装和编码,无需手动拼接邮件内容。
修正后的代码示例
import smtplib from email.message import EmailMessage # 自定义BBcode转HTML函数,根据实际规则调整 def bbcode_to_html(bbcode_str): html = bbcode_str.replace("[b]", "<strong>").replace("[/b]", "</strong>") html = html.replace("\n", "<br>") return html def send_subscription_email(smtp_server, smtp_port, smtp_user, smtp_pass, recipients, subject, plain_text, html_content, bbcode_content): # 处理BBcode转HTML(优先级:BBcode > 传入的HTML) final_html = bbcode_to_html(bbcode_content) if bbcode_content else html_content msg = EmailMessage() msg['Subject'] = subject msg['From'] = smtp_user msg['To'] = ', '.join(recipients) # 添加纯文本和HTML版本,指定UTF-8编码 msg.add_alternative(plain_text, subtype='plain', charset='utf-8') msg.add_alternative(final_html, subtype='html', charset='utf-8') # 发送邮件 with smtplib.SMTP(smtp_server, smtp_port) as server: server.starttls() server.login(smtp_user, smtp_pass) server.send_message(msg) # 调用示例 recipients = ["user1@example.com", "user2@example.com"] subject = "订阅更新通知" plain_text = "Hallo,\n\nGrüsse aus unserem Team!\n\nDein Abonnement wurde aktualisiert." html_content = "" bbcode_content = "[b]Hallo,[/b]\n\nGrüsse aus unserem Team!\n\nDein Abonnement wurde aktualisiert." send_subscription_email( smtp_server="smtp.example.com", smtp_port=587, smtp_user="your_email@example.com", smtp_pass="your_password", recipients=recipients, subject=subject, plain_text=plain_text, html_content=html_content, bbcode_content=bbcode_content )
验证要点
- 发送前可打印
msg.as_string(),检查MIME结构是否包含Content-Type: multipart/alternative; boundary=...,且各子部分有正确的Content-Type和charset=utf-8。 - 测试不同邮件客户端,确认HTML优先显示,纯文本作为备选正常展示,特殊字符无编码异常。
内容的提问来源于stack exchange,提问作者AceVanCleef
相关产品推荐
相关产品推荐

