一、FROM字段编码
1.问题
未知原因导致退信
服务器返回码:
SMTP error, DOT: Host qq.com(157.255.4.241) DOT said 550 The "From" header is missing or invalid. Please follow RFC5322, RFC2047, RFC822 standard protocol. [MIeJ6idQjpU+jtSwT+aVpzZn6Lt4t7L9L5SNdRRpvHFjruDr7ldlZXtjm76w== IP: 117.135.210.5]. https://service.mail.qq.com/detail/124/995.
由邮件返回信息可知是From字段出现了问题,查询163邮件合法性检查
邮箱From合法性检查
一、根据RFC5322协议,邮件标头中需要包含’From’信息。
二、根据RFC2047, RFC822协议,邮件标头中的’From’形式为:
1.邮箱地址形式:prefix@domain, 如 ‘abc@qq.com’。
2.昵称+空格+<邮箱地址>形式:nickname prefix@domain,其中,nickname为ASCII字符集中字符组合或编码文本:
如果昵称全为ASCII字符,如’ABC’,邮箱地址为’abc@qq.com’,则标头中的’From’为’ABC abc@qq.com‘。注意’ABC’和’abc@qq.com‘之间用空格隔开;
如果昵称包含非ASCII字符,如中文,则请使用base64对昵称进行编码。nickname最终的形式为:”=?” charset “?” encoding “?” encoded-text “?=”。其中,charset为字符集;encoding为编码方式,’B’代表base64;encoded-text为编码后的文本。例如,昵称为’QQ邮箱昵称示例’,邮箱地址为’abc@qq.com’,则对昵称进行base64编码,字符集使用UTF-8,则nickname为 ‘=?UTF-8?B?UVHpgq7nrrHmmLXnp7DnpLrkvos=?=’,最终邮件标头中的’From’为’”=?utf-8?B?UVHpgq7nrrHmmLXnp7DnpLrkvos=?=” abc@qq.com‘。注意编码文本和邮件地址间用空格隔开。
参考文献
https://www.rfc-editor.org/rfc/rfc5322
https://www.rfc-editor.org/rfc/rfc822
https://www.rfc-editor.org/rfc/rfc2047
2.解决
当From为中文的时候,需要满足格式
’”=?utf-8?B?你的字段编码后内容?=” abc@qq.com‘
1.需要对From要送的内容进行base64编码,字符集使用utf-8,然后前面拼接上”=?utf-8?B?,后面拼接上?=”,拼接之后有一个空格,再拼接上发送的邮箱地址(双引号可带可不带)
2.对From使用Header()函数赋值的时候不能使用utf-8编码
示例代码
import smtplib
from email.mime.text import MIMEText
from email.header import Header
import base64
sender = 'xxx@163.com'
pwd = 'FCPYYGMK'
receivers = ['123456@qq.com']
nickname='邮件测试'
encoded_nickname = '"=?UTF-8?B?' + base64.b64encode(nickname.encode('utf-8')).decode('utf-8') + f'?=" {sender}'
message = MIMEText('Python 邮件发送测试。。。', 'plain', 'utf-8')
message['From'] = Header(encoded_nickname)
message['To'] = Header('测试', 'utf-8')
subject = 'Python SMTP 邮件测试'
message['Subject'] = Header(subject, 'utf-8')
try:
smtpObj = smtplib.SMTP_SSL('smtp.163.com',465)
smtpObj.login(sender, pwd)
smtpObj.sendmail(sender, receivers, message.as_string())
print(message.as_string())
print('邮件发送成功')
except smtplib.SMTPException as se:
print(f'ERROR:无法发送邮件.Case:{se}')
-----------------------------------------------------------------
打印结果:
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
From: "=?UTF-8?B?6YKL6K+V?=" xxx@163.com
To: =?utf-8?b?5rK+V?=
Subject: =?utf-8?b?UHl0aG9uIFAg6YKu5Lu25rWL6K+V?=
UHl0aG9uIOmCruS7tuWAgea1i+ivleOAguOAguOAgg==
邮件发送成功
邮件接收:
二、附件中文名编码
1.问题
邮件添加附件"文件.txt",附件名是中文,能发送成功,但是接收后附件显示是bin文件
2.解决
与上面的问题一样,也是中文编码的问题,将中文部分进行编解码,拼接到字符串中(不可带双引号)
att1 = MIMEText(open('D:\\Downloads\\test.txt', 'rb').read(), 'base64', 'utf-8')
att1["Content-Type"] = 'application/octet-stream'
#如果文件名是中文需要做如下编解码处理
fname = '=?UTF-8?B?' + base64.b64encode('文本'.encode('utf-8')).decode('utf-8') + '?='
att1["Content-Disposition"] = f'attachment; filename="{fname}.txt"'
message.attach(att1)
重新发送,问题解决