Python发送邮件踩坑总结
因项目需要,要用公司邮箱向qq邮箱发送大概3000封邮件,发送过程中踩了不少坑,特地发出来分享一下
话不多说,先贴出来邮件发送代码,后面再讲坑。主要是针对于腾讯邮箱的550错误
发送基本信息配置
def send_email():
mail_info = {'mail_host': '服务器协议配置', 'mail_sender': '发送方邮箱',
'mail_login_name': '发送邮箱帐号', 'mail_pwd': '发送邮箱密码'}
title = '这里是邮件标题'
content = "这里是邮件内容"
# 构建发送对象信息,如果需要多用户分别发送则使用for循环,现在使用的方法发送的是两个人都能收到一样的邮件
# for recever in recever_list
# 如果使用for循环请假一个标志i=0 ,发一个就i+1,i限制300封,原因在最后会说
# generate_send_info(mail_info, title, content, recever)
generate_send_info(mail_info, title, content, ["123456789@qq.com", "23456789@qq.com"])
在这段代码里一定要注意:
1、mail_host的配置,因为使用的是公司专用邮箱,所以协议不一样,在这里卡了很久,报错也一直报的是邮箱帐号密码不正确,所以一定要注意这个地方存在的不同,这里的host配置是发送方的,而非接收方的且与接收方无关,如果使用qq邮箱发送,qq的配置就是’smtp.qq.com’。
2、generate_send_info构建的收件人里面,如果放到一个list里面则两个人都能收到一样的邮件,如果发给两个人不一样的信息则需要使用上述for循环分开发放
发送内容配置
def generate_send_info(mail_info, title, content, receiver):
# 睡1s防止给自己的邮箱服务器造成过大的压力,可根据自己需要调整
sleep(1)
# 邮件内容设置
message = MIMEMultipart()
# 邮件主题
message['Subject'] = title
# 发送方信息
message['From'] = mail_info['mail_sender']
# 邮件正文内容
message.attach(MIMEText(content, 'plain', 'utf-8'))
# 邮件附件为图片
with open('E:\图片路径信息\send1.jpg', 'rb')as fp:
picture = MIMEImage(fp.read())
# 与txt文件设置相似
picture['Content-Type'] = 'application/octet-stream'
picture['Content-Disposition'] = 'attachment;filename="send1.jpg"'
# 将内容附加到邮件主体中
message.attach(picture)
# 多名接受者同时发送,如果需要抄送加一条message['cc']就ok了
# 如果需要一名一名发送,接上述for循环且message['To'] = recevier 一名
# 经无意的测试这样也能发送,但是收到的很奇怪,不确定是否有影响,所以建议上述方法稳定些
message['To'] = recevier ','.join(receiver)
index = 0
flag = False
# 有的时候可能会在验证的时候出错,尝试三次,如果多次失败则报错不等待
while (index < 3):
index, flag = send_mail(mail_info, receiver, message, index)
if not flag:
print("send email to %s fail" % receiver)
else:
get_collection().update({"qq": receiver[0][:-7]}, {"$set": {"status": 1}})
print("send email to %s success" % receiver)
在这里有几个点一定要注意:
1、如果for循化发送多封,一定要根据自己的邮箱服务器情况让他休息一会,毕竟不小心就跑挂了就不好办了;
2、图片可以传多份,我使用的方法是再加一行with open如下,应该有更好的方法,我没有实验,欢迎提出来更好更简便的方法;
# 注意这里的as fp已经修改为f
with open('E:\图片路径信息\send2.jpg', 'rb')as f:
picture = MIMEImage(f.read())
# 与txt文件设置相似
picture['Content-Type'] = 'application/octet-stream'
picture['Content-Disposition'] = 'attachment;filename="send2.jpg"'
# 将内容附加到邮件主体中
message.attach(picture)
3、关于index<3,因为网络是不可靠的,有很多时候可能再发送的时候网络出问题导致验证出错了,邮件发送出问题了,这些不是我们的因素,只要交给程序就ok了,重试3次,如果一个人最后还是出错了也没关系,补发就好,大量出错,也能及时让我们感知,同样的,网络不可靠,在设计通过http协议获取某些参数的时候,也可以使用此方法,来减少人工要做的事;
4、关于传给一个人,但是不小心使用了
message['To'] = recevier ','.join(receiver)
这个样子的,实际的情况可能是这样的
没错,虽然能收到,但是这个收件人未免也太。。。了
5、如果是从数据库里读出数据,一定要加一个状态码来记录发送状态(是否发送过),不然电脑跑着跑着突然一个win10的惊喜更新,都不知道发送到哪里了,几百封邮件是不可能一封一封比对的(然后我确实这么干了,后面会贴一个比对outlook发件箱邮件信息的程序,不到万不得已一定不要使用,太麻烦了。。。)
最后一步:登录并发送邮件
def send_mail(mail_info, receiver, message, index):
# 登录并发送邮件
try:
smtpObj = smtplib.SMTP()
# 连接到服务器
smtpObj.connect(mail_info['mail_host'], 25)
# 登录到服务器
smtpObj.login(mail_info['mail_login_name'], mail_info['mail_pwd'])
# 发送
smtpObj.sendmail(mail_info['mail_sender'], receiver, message.as_string())
# 退出
smtpObj.quit()
return 3, True
except smtplib.SMTPException as e:
print("send email fail Exception %s" % e)
index = index + 1
return index, False
这里一般没有什么问题就是几个简单要注意的:
1、连接到服务器的端口默认是25,当然也有不默认的(┬_┬),当时因为这个端口和上面的协议,迷了好久
2、注意发送的邮箱和密码最好不要含有中文,否则就是编码错误,虽然可以解决(我觉得可以,但是没有尝试),但是多一事不如少一事,一定要稳
上述就是发邮件的代码,copy一下,启动一下send_email(),就ok了,最后说一下qq邮箱的各种550限制(因为这次主要是发送给qq邮箱的,所以暂时没有考虑163邮箱的一些限制信息)
1、如果使用一个邮箱,不是腾讯的企业邮箱了话要注意:
腾讯邮箱存在差不多相当于发送广告邮箱鉴别的亚子,返回邮件大概是这样的
附件里面的那个小邮件一样的标志(我打码)就是本次发送的邮件,这个附件有可能有有可能没有(什么原因不知道),这不是关键,关键是下面的错误信息 550 Sender frequency limited 发放超限。点开链接:
既然是商业机密,也就只能大概估计一下,我这次算的大概一天300封邮件就把我拉黑,所以在上面的for循环中加一个300的限制,每个应该是不同的,300只是我的实际猜测(其实有的号可以再多10封左右,就会拉黑)
这个问题充钱就能解决(搞个腾讯企业邮箱),否则就和我一样多申请几个,多弄几天发
2、还有一种神奇的错误
这个错误的原因,打开链接也可以看到
没错,就是这个用户没有开通qq邮箱,具体为什么没开通(可能这个号就是用来专门干啥的,比如我就有个号专门用来打游戏,所以存在没开通的情况,这个就自己处理~)
最后我等会会更新一个读取outlook里面的邮件的信息的方法,用来告诉大家我3000封邮件中在当时遇到win10惊喜更新的时候校验有没有漏发的情况