Python发送含附件邮件时,发件人含德语变音符号触发合规错误
解决Python发送带附件邮件时发件人显示名含德语变音符号的RFC合规问题
问题场景
在Windows系统使用Python 3.11发送带附件邮件时,当发件人显示名(或邮箱地址)包含德语变音符号äöü,发送服务器会提示邮件不符合RFC 5321/5322标准;移除变音符号则可正常发送。相关最小复现代码如下:
import smtplib import ssl from email import encoders from email.mime.base import MIMEBase from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart message = MIMEMultipart() message.set_charset('utf-8') subject = 'Support-Nr. 1' message["Subject"] = subject body = 'testmail 123 äöüß' message.attach(MIMEText(body, "plain")) filename = 'VCARD_A & B.vcf' with open(filename, "rb") as attachment: part = MIMEBase("application", "octet-stream") part.set_payload(attachment.read()) encoders.encode_base64(part) part.add_header( "Content-Disposition", f"attachment; filename= {filename}", ) message.attach(part) sender_email = 'email1@example.com' receiver_email = 'email2@example.com' displayname = 'Höhne' message["From"] = displayname + '<' + sender_email + '>' message["To"] = receiver_email smtplogin = # loginname smtppassword = # passwort smtpserver = 'smtp.ionos.de' smtpport = 465 context = ssl._create_unverified_context() with smtplib.SMTP_SSL(smtpserver, smtpport, context=context) as server: server.login(smtplogin, smtppassword) server.sendmail(sender_email, receiver_email, message.as_string())
问题原因
直接拼接显示名与邮箱地址作为From头,会让非ASCII字符(如ö)以原始UTF-8格式出现在邮件头中。而RFC 5321/5322明确要求,邮件头中的非ASCII字符必须按照RFC 2047标准进行编码(quoted-printable或Base64格式),否则服务器会判定邮件不合规。
解决方案
使用Python标准库email.utils中的formataddr函数构造From头,该函数会自动检测并编码非ASCII字符,确保邮件头符合RFC标准。
修改后的代码
import smtplib import ssl from email import encoders from email.mime.base import MIMEBase from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart # 新增导入 from email.utils import formataddr message = MIMEMultipart() message.set_charset('utf-8') subject = 'Support-Nr. 1' message["Subject"] = subject body = 'testmail 123 äöüß' message.attach(MIMEText(body, "plain")) filename = 'VCARD_A & B.vcf' with open(filename, "rb") as attachment: part = MIMEBase("application", "octet-stream") part.set_payload(attachment.read()) encoders.encode_base64(part) # 可选:处理附件文件名的特殊字符编码 from email.header import encode_header encoded_filename = encode_header(filename, 'utf-8').decode() part.add_header( "Content-Disposition", f"attachment; filename= {encoded_filename}", ) message.attach(part) sender_email = 'email1@example.com' receiver_email = 'email2@example.com' displayname = 'Höhne' # 替换原From头构造方式 message["From"] = formataddr((displayname, sender_email)) message["To"] = receiver_email smtplogin = # loginname smtppassword = # passwort smtpserver = 'smtp.ionos.de' smtpport = 465 context = ssl._create_unverified_context() with smtplib.SMTP_SSL(smtpserver, smtpport, context=context) as server: server.login(smtplogin, smtppassword) server.sendmail(sender_email, receiver_email, message.as_string())
关键修改点
- 导入
email.utils.formataddr函数,用于合规构造发件人地址 - 将原
message["From"] = displayname + '<' + sender_email + '>'替换为message["From"] = formataddr((displayname, sender_email)) - (可选)用
email.header.encode_header处理附件文件名,避免特殊字符引发的编码问题
内容的提问来源于stack exchange,提问作者Erbs
相关产品推荐
相关产品推荐

