Python3中Gmail SMTP邮件References头设置与IMAP读取异常问题
解决Python SMTP发送邮件时References头乱码问题
问题场景
使用Python 3.8的smtplib和email.message.EmailMessage发送Gmail邮件时,设置References头后,邮件发送无报错,Gmail原始邮件显示正常,但用imaplib的email.message_from_bytes读取时,References头出现大量QP编码的乱码(如=?utf-8?q?=22=3CBN8PR17...),而Message-ID和In-Reply-To显示正常。
原始设置代码:
reference_ids = [ '<BN8PR17MB27372595A957D7912CEE184FBF6F9@BN8PR17MB2737.namprd17.prod.outlook.com>', '<CAM9Ku=FZ5RGMvw3VzNrZz+DA78zyq2Am8fz9JNLmjUQ9ZEXpDQ@mail.gmail.com>', '<BN8PR17MB27371C71A65834531DF028BBBF6F9@BN8PR17MB2737.namprd17.prod.outlook.com>', '<CAM9Ku=E1wmpj=AMRhsh-Sk1RHqmK_x-J5ey8szVehefYQvn13w@mail.gmail.com>'] in_reply_to = reference_ids[0] smtp = smtplib.SMTP_SSL(es.smtp_server) smtp.login(es.username, es.password) msg = email.message.EmailMessage() if (reference_ids is not None): msg.add_header('In-Reply-To', in_reply_to) msg.add_header('References', (' ').join(reference_ids)) msg['Subject'] = request.vars.subject msg['From'] = es.email msg['To'] = request.vars.to msg['CC'] = request.vars.cc msg['BCC'] = request.vars.bcc msg.set_content(request.vars.message) smtp.send_message(msg) smtp.quit()
读取到的异常References头内容:
References: =?utf-8?q?=22=3CBN8PR17MB27372595A957D7912CEE184FBF6F9=40BN8PR17?= =?utf-8?q?MB2737=2Enamprd17=2Eprod=2Eoutlook=2Ecom=3E?= <CAM9Ku=FZ5RGMvw3VzNrZz+DA78zyq2Am8fz9JNLmjUQ9ZEXpDQ@mail.gmail.com> =?utf-8?q?=3CBN8PR17MB27371C71A65834531DF028BBBF6F9=40BN8PR17MB2737=2Enampr?= =?utf-8?q?d17=2Eprod=2Eoutlook=2Ecom=3E_=3CBN8PR17MB27377F609B669D0E72638D6?= =?utf-8?q?9BF6F9=40BN8PR17MB2737=2Enamprd17=2Eprod=2Eoutlook=2Ecom=3E?= <CAM9Ku=E1wmpj=AMRhsh-Sk1RHqmK_x-J5ey8szVehefYQvn13w@mail.gmail.com>
问题原因
EmailMessage.add_header()方法默认会将内容视为非结构化文本,对其中的特殊字符或过长内容进行QP(Quoted-Printable)编码,但References和In-Reply-To属于结构化邮件头,由标准格式的Message-ID组成,不需要编码。使用add_header会错误触发编码逻辑,导致后续读取时出现乱码。
解决方案
直接通过字典赋值方式设置这些结构化头,而非调用add_header方法,EmailMessage会自动按照邮件标准处理结构化头的格式,避免不必要的编码:
修改后的核心代码:
if reference_ids: msg['In-Reply-To'] = in_reply_to msg['References'] = ' '.join(reference_ids)
读取时的注意事项
读取邮件时,使用email.policy.default策略替代默认的兼容策略,确保正确解码结构化头:
import imaplib import email # 连接IMAP服务器并获取邮件字节流(省略连接逻辑) ... msg = email.message_from_bytes(email_bytes, policy=email.policy.default) # 获取正确的References内容 references = msg.get('References', '')
这种方式会自动处理编码后的头内容,直接返回原始的Message-ID列表字符串,不会显示乱码。
内容的提问来源于stack exchange,提问作者lucas
相关产品推荐
相关产品推荐

