https://blog.csdn.net/yfreedomliTHU/article/details/88196631
需求背景:最近同学需要收集一些调研问卷,立马想到了群发邮件这一方式,机智地用excel按照邮件格式造了一堆学校邮箱,打算一个一个复制粘贴群发。好家伙,这么多邮箱得粘贴到猴年马月啊,极其精污。作为略懂点python的弱鸡,当然要在这个问题上装个逼了,一口答应了同学用python给他写个脚本,当然就踩到了各种坑了。网上各种python群发邮件的教程都有,没错,就是用smtplib这个包基本可以实现,但是写完之后却发现遇到无效的邮箱程序自动抛出错误就停止了,邮件倒是一个都没发出去。在网上找了很久,都没找到啥教程。最后我貌似阴差阳错找到了可能有效的替代方法,因此记录一下,供大家讨论学习。
步骤:使用python中的smtplib群发邮件主要可以分为以下几个步骤:
1.开通邮箱的第三方授权,注意记下授权码;
2.创建smpt对象,连接smpt服务器(注意不通邮箱的端口不同);
3.登录自己的邮箱账号(注意密码是1中开通第三方授权的授权码,而不是登录密码);
4.通过发送消息函数发送邮件,需要设置发件人、收件人(群发为多个收件人),内容,标题等参数;
5.发送成功,关闭连接。
为了比较清楚地了解具体的流程,下面我将以QQ邮箱为例。进行简单的说明。
一、开通邮箱的第三方授权
QQ邮箱开通授权的步骤可以参考这篇博客:https://blog.csdn.net/SpiderManSun/article/details/84964171
简单来说就是:登入你的QQ邮箱,点击设置–账户,然后找到POP3/SMTP或者IMAP/SMTP服务,二者选其一就行,这里我们只需要SMTP,然后会通知你给腾讯科技的电话发邮件,之后会告诉你一个授权码,这个授权码需要记住,后面需要用。
二、创建对象,设置参数
这一部分网上的教程比较多,就不过多赘述了,只说几个需要注意的点:
1.smpt server的host:这个不同邮箱有所不同,例如QQ邮箱就是:smpt.qq.com
2.mail_user和sender均为发件人邮箱,mail_pass为授权码,并非邮箱登录密码
3.群发邮件有多个收件人,需要用.join()函数添加,即:message[‘To’] = “,”.join(receiver)
import smtplib
from email.header import Header
from email.mime.text import MIMEText
import csv
import pandas as pd
# SMTP Service
mail_host = "smtp.qq.com" # SMTP server, take QQ for example
mail_user = "xxx@qq.com" # user
mail_pass = "xxxxxxxxxx" # note:Authorization Code,not password
sender = "xxx@qq.com" # sender email
#get receiver email from cvs file
def get_email():
with open('test.csv','r') as csvfile:
reader = csv.reader(csvfile)
row1 = [row for row in reader]
data = row1[0]
print(data)
print(len(data))
return data
#write the content and title of your email here!
def email_content():
title = 'python_email_test' # title
content = 'Test success!' # content of your email
return title,content
def sendEmail():
title,content = email_content()
#receiver = get_email()
bcc = get_email() # 接收邮件,可设置为你的QQ邮箱或者其他邮箱,加入bcc实现密送
message = MIMEText(content, 'plain', 'utf-8') # content, format, encoding
message['From'] = "{}".format(sender)
#message['To'] = ",".join(receiver) #To:收件人,Cc:抄送,Bcc:密送,不显示地址
message['Bcc'] = ",".join(bcc)
message['Subject'] = title
try:
smtp_Obj = smtplib.SMTP_SSL(mail_host, 465) # 启用SSL发信, 端口一般是465
smtp_Obj.login(mail_user, mail_pass) # 登录验证
#smtp_Obj.sendmail(sender, receiver, message.as_string()) # send
smtp_Obj.sendmail(sender, bcc, message.as_string())
print("email send success!")
except smtplib.SMTPException as e:
print(e)
print("error!email send failed!")
if __name__ == '__main__':
sendEmail()
注意这几点基本就能实现简单的群发邮件了,但是在实际运行过程中会发现如果遇到无效的邮箱地址,会导致程序抛出错误,该批邮箱均无法成功发出邮件。
运行结果如下:
输入正确邮箱和错误邮箱,但是会导致两个均无法接受到邮件,这在群发邮件中是很让人头疼的问题。为了解决这个问题,翻了网上大部分教程都没有解决,本来就要放弃了,却因为群发邮件的另一个需求而阴差阳错的解决了,下面听我慢慢道来。
契机:像这种调研问卷直接让每个收件人看到所有的群发收件人是不合适的,容易引起反感,也无法营造出被问卷调查人是被偶然抽中的(废话!当然是怕被骂啊!),因此想实现类似手动群发中的群发单显功能,由于时间有限,当然没有实现完整的群发单显功能,通过查阅smtplib的说明文档,我发现可以通过简单设置一下参数就可实现抄送,密送功能,这种发骚扰问卷,当然密送最好了,最后就选了密送。
了解一下什么是抄送、密送,可以参考:https://www.zhihu.com/question/19670232
具体的实现问题可以参考Stack Overflow的讨论:https://stackoverflow.com/questions/1546367/python-how-to-send-mail-with-to-cc-and-bcc
注意:To列表:所有收件人邮箱;Cc列表:抄送;放入Bcc列表:密送,不能看见收件人邮箱,只能看到发件人邮箱地址。
简单总结一下:只要把收件人的邮箱都添加在 bcc 列表里就可以保证单个收件人只可以看到自己的邮箱,而无法看到所有收件人的邮箱。
下面重点来了!在将所有的收件人均放到message[‘Bcc’]后,我发现不但成功解决了显示邮箱的隐私泄露问题,还成功解决了错误邮箱不能跳过的问题。采用密送形式群发邮件,smtplib就能自动跳过无效邮箱,只发送给有效邮箱,成功解决了两大问题,也成功发完了所有的问卷,避免了人工筛选的繁杂工作。
当然,这里的无效邮箱也不是完全非法形式,主要是针对正确邮箱形式的无效邮箱。其实在用QQ邮箱测试的时候发现QQ会自动退订,这种情况下不会出现有错误邮箱发不出的因素。本文针对的更多是学校的教育邮箱或者公司邮箱不能对错误邮箱作出自动退回的邮箱,这种情况下一有报错就可能会导致全部发送失败,这时候可以试着采用密送的形式,就能跳过无效邮箱了。
简单总结一下,实现python群发邮件可能会出现错误邮箱导致全部发送失败,可以尝试改为密送方式,这时候可以自动跳过这些错误邮箱,当然还有前提条件:没有自动退回功能的自建邮箱,如学校邮箱等。当然不同邮箱的差别很大,这种方法可能也不一定完全适用,如果不适用,本文也可以提供密送邮件的解决办法嘛。
参考:
1.QQ邮箱SMTP授权:https://blog.csdn.net/SpiderManSun/article/details/84964171
2.知乎:什么是抄送、密送:https://www.zhihu.com/question/19670232
3.Stack Overflow的实现:https://stackoverflow.com/questions/1546367/python-how-to-send-mail-with-to-cc-and-bcc