You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用email.parser.Parser创建邮件消息时的Unicode编码错误问题排查与解决

两种邮件创建方式的Unicode处理差异原因及解决方法

差异原因

咱们先拆解下两种方式的核心区别:

  • 用email.message.EmailMessage()直接构建消息时,这个类的设计就是原生支持Unicode的。不管是设置头部(比如msg['Subject'])还是调用set_content(),它都会自动按照email.policy.default的规则处理:

    • 头部里的Unicode字符会被自动编码成RFC 2047格式(比如déjeuner会变成=?utf-8?q?d=C3=A9jeuner?=),完全符合邮件标准对头部的编码要求;
    • 正文内容会自动设置Content-Type: text/plain; charset="utf-8"和对应的传输编码,smtplib发送时能直接识别并正确处理。
  • 而用email.parser.Parser().parsestr()解析字符串的方式,问题出在你传入的是包含原生Unicode字符的字符串。Parser的parsestr方法会把整个消息当作“已经解码完成的文本”,不会自动对头部的Unicode字符做RFC 2047编码。当smtplib的send_message()尝试把消息转换为字节流发送时,它默认会用ASCII编码处理头部,遇到à、é这类非ASCII字符自然就抛出UnicodeEncodeError了。

解决方法

最靠谱的解决方式是用BytesParser解析字节流,因为邮件在传输层本质就是字节流,这种方式更贴合邮件的实际格式:

msgsource = """\
From: sender@example.com
To: recipient@example.com
Subject: Ayons asperges pour le déjeuner

Cela ressemble à un excellent recipie déjeuner.
"""
# 将字符串转为UTF-8编码的字节流
msg_bytes = msgsource.encode('utf-8')
# 使用BytesParser解析字节流,而非Parser解析字符串
msg = email.parser.BytesParser(policy=email.policy.default).parsebytes(msg_bytes)

这样处理后,BytesParser会正确识别字节流的UTF-8编码,自动把头部的Unicode字符转为符合标准的RFC 2047格式,正文也会正确设置编码信息,smtplib发送时就不会再报错了。

如果你确实需要用字符串解析,也可以在解析后手动为消息补全编码处理,但这种方式不如字节流解析直接:

msg = email.parser.Parser(policy=email.policy.default).parsestr(msgsource)
# 手动重置正文的编码设置
msg.set_content(msg.get_content(), charset='utf-8')
# 手动重新编码所有头部,触发自动转RFC 2047格式的逻辑
for header_name in ['Subject', 'From', 'To']:
    value = msg[header_name]
    del msg[header_name]
    msg[header_name] = value

不过这种方式需要额外处理头部,不如第一种方法简洁可靠。


内容的提问来源于stack exchange,提问作者VPfB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 14:14:09