关于 Python3.6.3 写简单发送邮件代码时遇到的新浪邮箱(2018/7/29)的问题

注:作者编程小白,高手勿喷,如有疏漏,还请指正!

近期在跟着廖大大的教程学 Python,正好看到 SMTP发送邮件,于是乎自己尝试了一下,不(好)巧,自己主要用的是新浪邮箱,遇到了一些问题。在此记录一下。

“最简单的纯文本邮件”

from email.mime.text import MIMEText
msg = MIMEText('hello, send by Python...', 'plain', 'utf-8')

# 输入Email地址和口令:
from_addr = input('From: ')
password = input('Password: ')
# 输入收件人地址:
to_addr = input('To: ')
# 输入SMTP服务器地址:
smtp_server = input('SMTP server: ')

import smtplib
server = smtplib.SMTP(smtp_server, 25) # SMTP协议默认端口是25
server.set_debuglevel(1)
server.login(from_addr, password)
server.sendmail(from_addr, [to_addr], msg.as_string())
server.quit()

运行结果报错:

smtplib.SMTPDataError: (553, b'Envolope sender mismatch with header from..')

代码中 msg 的第一个参数不论怎么改都会报相同的错!下面我会提到为什么单独对这个参数进行分析……

msg = MIMEText('XXX', 'plain', 'utf-8')
# “XXX”随便改什么 string

“一封完整的邮件”

from email import encoders
from email.header import Header
from email.mime.text import MIMEText
from email.utils import parseaddr, formataddr

import smtplib

def _format_addr(s):
    name, addr = parseaddr(s)
    return formataddr((Header(name, 'utf-8').encode(), addr))

from_addr = input('From: ')
password = input('Password: ')
to_addr = input('To: ')
smtp_server = input('SMTP server: ')

msg = MIMEText('hello, send by Python...', 'plain', 'utf-8')
msg['From'] = _format_addr('Python爱好者 <%s>' % from_addr)
msg['To'] = _format_addr('管理员 <%s>' % to_addr)
msg['Subject'] = Header('来自SMTP的问候……', 'utf-8').encode()

server = smtplib.SMTP(smtp_server, 25)
server.set_debuglevel(1)
server.login(from_addr, password)
server.sendmail(from_addr, [to_addr], msg.as_string())
server.quit()

这一次发现打印信息表示发送成功

data: (250, b'ok queue id 420484393705')
send: 'quit\r\n'
reply: b'221 smtp-5-123.smtpsmail.fmail.xd.sinanode.com\r\n'
reply: retcode (221); Msg: b'smtp-5-123.smtpsmail.fmail.xd.sinanode.com'

然而打开收件邮箱查看是否收到时,却发现并没有!然后再次尝试修改 msg 的第一个参数:

msg = MIMEText("from:[email protected], send by Python...", 'plain', 'utf-8')
#“XXX”替换为发件箱的地址

再次尝试,发现——收件箱收到邮件了!

为什么会修改变量 msg ?

在测试“最简单的文本邮件”遇到报错问题时也搜索了很多的解决方案并尝试,其中发现有一种做法就是直接用 string 定义邮件正文内容

msg = """
to:%s
from:%s
Hello,I am smtp server
""" %(to_addr, from_addr)
...
server.sendmail(from_addr, [to_addr], msg)

这个时候发现居然可以收到邮件了(尽管会有“仔细观察,发现如下问题”)!

“Envolope sender mismatch with header from..”

关于这个报错百度了不少解决方案,发现并没有一个跟我发现的情况一样。大概意思应该是 smtp.sina.com 会解析邮件正文内容,如果里面包含“from:[email protected]”信息,与 msg [‘From’] 一致,就算作 match。

但是在具体的各种试验的时候发现还是有点不太理解其中的规则,后面有时间再深入研究一下吧(应该给 smtp.sina.com 提交个 bug 先 :-p)!

一些简单的测试结果:

简单/完整 msg类型 msg值/参数值 发件人定义 测试结果
简单文本 MIMEText 参数1不包含 “From:[email protected] from_addr = “[email protected] 报错mismacth
简单文本 MIMEText 参数1包含 “From:[email protected] from_addr = “[email protected] 报错mismacth
简单文本 string 不包含string “From:[email protected] from_addr = “[email protected] 报错mismacth
简单文本 string 包含string “From:[email protected] from_addr = “[email protected] 成功发送 & 接收成功
完整邮件 MIMEText 参数1不包含 “From:[email protected] from_addr = “[email protected] 报错mismacth
完整邮件 MIMEText 参数1包含 “From:[email protected] from_addr = “[email protected] 报错mismacth
完整邮件 MIMEText 参数1不包含 “From:[email protected] msg [‘From’] = XXX 发送成功 & 接收失败
完整邮件 MIMEText 参数1包含 “From:[email protected] msg [‘From’] = XXX 发送成功 & 接收成功

测试@2018/7/29 13:39

发现还有不少问题,HTML内容好像可以成功,但是加上附件了又收不到邮件,不知道为什么。附上测试用的代码,可自行修改对应的用户名、密码进行测试。

测试@2018/7/29 13:50

发现带附件发的话原来进了QQ邮箱的垃圾箱,所以还是可以成功发送并接收的!

# https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001432005226355aadb8d4b2f3f42f6b1d6f2c5bd8d5263000

from email import encoders
from email.header import Header
from email.mime.text import MIMEText
from email.utils import parseaddr, formataddr
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
import smtplib

def _format_addr(s):
    name, addr = parseaddr(s)
    return formataddr((Header(name, 'utf-8').encode(), addr))

#定义“结构体”init_smtp_info()
class MyClass():
    def __init__(self, name = ""):
        self.name = name
        self.data_dic = {}
        self.index = -1

    class Struct():
        def __init__(self, from_addr, password, smtp_server, to_addr, msg):
            self.from_addr = from_addr
            self.password = password
            self.smtp_server = smtp_server
            self.to_addr = to_addr
            self.msg = msg

    #return struct item.
    def init_smtp_info(self, from_addr, password, smtp_server, to_addr, msg):
        return self.Struct(from_addr, password, smtp_server, to_addr, msg)

#创建smtp_info集实例
smtp_info_collection = MyClass()

#通用-直接定义收件人
to_addr = "XXX@XX" #请对应修改指定收件邮箱信息

#通用-定义邮件正文内容
msg1 = MIMEText("from:[email protected], send by Python...", 'plain', 'utf-8') #请对应修改邮箱信息
msg2 = MIMEText("hello, send by Python...", 'plain', 'utf-8')
msg3 = MIMEText('

Hello

'
+ '

send by Python...

'
+ '', 'html', 'utf-8') #定义带附件的邮件内容 msg4 = MIMEMultipart() msg4.attach(msg1) with open('XXX', 'rb') as f: #请对应修改图片文件信息 # 设置附件的MIME和文件名,这里是jpg类型: mime = MIMEBase('image', 'jpg', filename='XXX.jpg') #请对应修改图片文件信息 # 加上必要的头信息: mime.add_header('Content-Disposition', 'attachment', filename='XXX.jpg') #请对应修改图片文件信息 mime.add_header('Content-ID', '<0>') mime.add_header('X-Attachment-Id', '0') # 把附件的内容读进来: mime.set_payload(f.read()) # 用Base64编码: encoders.encode_base64(mime) # 添加到MIMEMultipart: msg4.attach(mime) #确定到底使用哪个msg msg = msg4 #单独-定义发件人(QQ邮箱) from_qq_addr = "[email protected]" #请对应修改QQ邮箱信息 pswd_qq = "XXX" #请对应修改QQ邮箱信息 smtp_qq_server = "smtp.qq.com" #初始化qq邮箱实例 info_qq = smtp_info_collection.init_smtp_info(from_qq_addr,pswd_qq,smtp_qq_server,to_addr,msg) #单独-定义发件人(新浪邮箱) from_sina_addr = "[email protected]" #请对应修改新浪邮箱信息 pswd_sina = "XXX" #请对应修改新浪邮箱信息 smtp_sina_server = "smtp.sina.com" #初始化新浪邮箱实例 info_sina = smtp_info_collection.init_smtp_info(from_sina_addr,pswd_sina,smtp_sina_server,to_addr,msg) #定义被调用的发件人信息(当前新浪邮箱,用#进行切换) #finalized_info = info_qq finalized_info = info_sina #通用-定义与发送邮件部分 msg['From'] = _format_addr('Python <%s>' % finalized_info.from_addr) msg['To'] = _format_addr('Target <%s>' % finalized_info.to_addr) msg['Subject'] = Header('来自%s的问候……' % finalized_info.from_addr, 'utf-8').encode() #打印完整的msg信息(编码后) print("\r\n\r\nContent of msg:\r\n"+msg.as_string()) #打印与服务器交互信息 print("\r\n\r\n\r\n%s:\r\n" % finalized_info.smtp_server) if finalized_info.smtp_server == "smtp.qq.com": server = smtplib.SMTP_SSL(finalized_info.smtp_server, 465) elif finalized_info.smtp_server == "smtp.sina.com": server = smtplib.SMTP(finalized_info.smtp_server, 25) server.set_debuglevel(1) server.login(finalized_info.from_addr, finalized_info.password) if type(msg) == type("string"): server.sendmail(finalized_info.from_addr, [finalized_info.to_addr], msg) elif type(msg) != type("string"): server.sendmail(finalized_info.from_addr, [finalized_info.to_addr], msg.as_string()) server.quit()

你可能感兴趣的:(小白辛酸之路)