Home > Article > Backend Development > Teach you a python code example to make an automatic email script
This article mainly introduces the relevant knowledge of Python automatic email script. It has a very good reference value. Let’s take a look at it with the editor.
Origin
During this period, I created a script for sending group emails to friends. In order to prevent I have done a lot of work to get into spam. I just finished it and the entry rate of spam is 50%, which I think is not bad. If I want to lower the entry rate of spam, I will probably have to spend money to buy a host. Just think about it. , launch it for a month first, see the effect and then expand.
The script is mainly written in Python, and the smtplib library is adjusted. These are the basics. You can search a lot on the Internet. Today I will mainly explain to you how to avoid entering the spam system and how to build the entire system. some thoughts. Maybe I have just started Python, and there are many possible wrong writing methods that I hope you can point out~
Configuration
CentOS7.0 system
Python 3.4
The default version under CentOS7.0 is Python2.7.5. Let’s first upgrade the Python version.
#wget https://www.python.org/ftp/python /3.4.3/Python-3.4.3.tgz
Download Python3.4 version
#tar -xf Python-3.4.3.tgz #cd Python-3.4.3/ #./configure
When you configure here, you may encounter that your environment does not have a gcc compilation environment installed. , execute the following statement and then configure
#yum -y install gcc #yum -y install gdb #yum -y install gcc-c++
Compile and install
#make #make install
Because yum may not work properly after replacing the python version, two files need to be changed
#vim /usr/bin/yum #vim /usr/libexec/urlgrabber-ext-down
Change the #!/usr/bin/python in the header of these two files to #!/usr/bin/python2.7, save and exit, and revive the yum full state.
After compiling, python3 .4 is set as the default python parsing.
#ln -s /usr/local/bin/python3.4 /usr/bin/python
Check the python version after the link is completed
#python -V
The appearance of Python3.4 indicates that the version switch is completed
System architecture
Account: Directory used to store the sender’s email account. My 163 email, sina email, sohu email and tom email all purchased 30 accounts on Taobao that can send SMTP services for the cost of a meal. You can get it if you don’t have it~ The account password is separated by [:], and each account is separated by [,].
Common: Reference class folder, which contains the daily system configuration file and log system source code
Conf: Global configuration file, currently not useful
Image: Image resources that need to be used in the process of sending emails
Log: Log files, distinguished by date
Logbackups: Log backup files, used to back up expired logs
Sendmail: Use To store the recipient's email information, use [,] to separate the accounts
mail_html.py: Mainly execute the script
README.md: User instructions for git version control, I use code Cloud manages my code
Log system
When it comes to script systems, logs play a very critical role, especially when your script makes an error, you have to check When it is wrong, it is very important. I also got a piece of code for the Log logging system from the Internet. I think it is very useful and for everyone’s reference~
The main idea is to print the log to the specified file and print the log. When I get to the screen, I won’t say anything else. Let’s start with the code. Since it’s the code from the Internet, I’ll put it up~
# coding: utf-8 #from lxml import etree import logging.handlers import logging import os import sys import time import datetime try: import xml.etree.cElementTree as ET except ImportError: import xml.etree.ElementTree as ET # 提供日志功能 class logger: # 先读取XML文件中的配置数据 # 由于config.xml放置在与当前文件相同的目录下,因此通过 __file__ 来获取XML文件的目录,然后再拼接成绝对路径 # 这里利用了lxml库来解析XML root = ET.parse(os.path.join(os.path.dirname(__file__), 'config.xml')).getroot() # 读取日志文件保存路径 logpath = root.find('logpath').text # 读取日志文件容量,转换为字节 logsize = 1024*1024*int(root.find('logsize').text) # 读取日志文件保存个数 lognum = int(root.find('lognum').text) # 添加分天日志名 now = datetime.datetime.now() now_time = now.strftime('%Y%m%d') log_file_name = sys.argv[0].split('/')[-1].split('.')[0] + '_' + now_time # 日志文件名:由用例脚本的名称,结合日志保存路径,得到日志文件的绝对路径 logname = os.path.join(logpath, log_file_name) # 初始化logger log = logging.getLogger() # 日志格式,可以根据需要设置 fmt = logging.Formatter('[%(asctime)s][%(filename)s][line:%(lineno)d][%(levelname)s] %(message)s', '%Y-%m-%d %H:%M:%S') # 日志输出到文件,这里用到了上面获取的日志名称,大小,保存个数 handle1 = logging.handlers.RotatingFileHandler(logname, maxBytes=logsize, backupCount=lognum) handle1.setFormatter(fmt) # 同时输出到屏幕,便于实施观察 handle2 = logging.StreamHandler(stream=sys.stdout) handle2.setFormatter(fmt) log.addHandler(handle1) log.addHandler(handle2) # 设置日志基本,这里设置为INFO,表示只有INFO级别及以上的会打印 log.setLevel(logging.INFO) # 日志接口,用户只需调用这里的接口即可,这里只定位了INFO, WARNING, ERROR三个级别的日志,可根据需要定义更多接口 @classmethod def info(cls, msg): cls.log.info(msg) return @classmethod def warning(cls, msg): cls.log.warning(msg) return @classmethod def error(cls, msg): cls.log.error(msg) return
Configuration file of the log system
<?xml version="1.0" encoding="utf-8"?> <config> <!-- 日志保存路径 --> <logpath>/Users/litao/Desktop/mail_html/Log</logpath> <!-- 每个脚本对应的日志文件大小,单位MB --> <logsize>8</logsize> <!-- 每个脚本保存的日志文件个数 --> <lognum>100</lognum> </config>
You can save the path as you like. .
How to use
logger.info('邮件总数量【'+str(len(recivers))+'】') logger.info('总计发送邮件数量【'+str(send_num)+'】') logger.info('总计发送错误数量【'+str(error_num)+'】') logger.info('成功邮箱账号集合:'+','.join(send_success_account)) logger.info('失败邮箱账号集合:'+','.join(send_failure_account)) logger.info('脚本结束------------------------------------------------------------------') logger.info('')
If you want error, just replace info with error
Execute the main file
File spam, everyone The first thing that comes to mind is that annoying marketing email in the trash can. However, if the content of your email is well written, can you avoid being blocked? The answer is no, the email is blocked by a machine. If If it's a machine that does it, then it's easy. First, we have to know how the machine works.
Most of the emails classified as spam have two characteristics: the content remains unchanged and the IP remains unchanged. In fact, if the content keeps changing and the IP keeps changing, it can theoretically avoid entering the spam mailbox. But there are not so many manpower and material resources to do this, so what we have to do is to solve probabilistic problems.
Content confusion
The content remains unchanged. We can use multiple sets of templates and nest them. This problem is easy to solve, but the IP remains unchanged. , this is a bit more difficult. In fact, I haven’t solved it yet. The main reason is that I am afraid of spending money. What I can do is to use multiple sets of templates to prevent the content from being blocked.
Okay, let’s first prepare 30 email subjects and 30 sets of email content templates. Here is my global subject configuration
How to do this The advantage is that it can prevent the content of the email from being blocked. Suppose we send an email every 30 seconds, then none of the emails within 20 minutes will be duplicated. We consider it from the perspective of accepting email domain names, that is, if our marketing targets are all QQ mailboxes, then the mail content of the same IP received by the mailbox server of QQ mailbox within 20 minutes will be different, which is to a large extent You can avoid being banned.
账户混淆
设置这么多账号是干嘛用的呢,主要还是想混淆机器,让垃圾邮件进率更低。
下面我个人经过测试,发现邮箱服务器具有的一些特性。
163邮箱
163邮箱设置了每天每个账号邮件发送的上限位50封,账号554出错重发的时间是3小时。
tom邮箱
tom邮箱每天邮件发送数量不做限制,我们也假设是50封,但是每封邮件之间的发送间隔一定要超过30秒,要不然会被短时间连接数过大报错。
sohu邮箱
业界良心,基本上没出过啥错误,一直保持着良好的发送成功率。我们也将其定位发送间隔30秒,每日上线50封。
sina邮箱
恶心的玩意儿,每次发送邮箱前需要先登录,认证手机号,每个手机号5个邮箱哈,但是效果显著,认证完毕,和sohu一样,基本没出错过。
时间混淆
有了这些基础,我们就可以知道了,我们有120个账号,30个邮件模板,每天一刻不停的发送,每封邮件之间的间隔为30秒,一天的邮件发送量在2800封左右。
我觉得一天2800封,如果有钱的话,一台ESC的费用是3元每天,独立ip哈,如果找第三方发送,一封邮件是3分钱,量大2分钱,他们是EDM的,我测试过1500封,达到率不足千分之一。也就是说,我们发送1500封,只需要1块多钱,找第三方发送,1500封怎么也得40块钱。成本是不是很低。
好的,那就来看看邮件是如何发送的吧。
邮件发送
下面我们来看下我的主文件是如何搞的
#coding=utf-8 import smtplib import mimetypes import time import datetime from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart from email.mime.image import MIMEImage #引入外部文件 from Common.log import *
导入模块,以来的外部库和内部的文件
#目录主位置
_root_dir = '/Users/litao/Desktop/mail_html/'
_title_common = '愚人节'
愚人节主题礼物,也是为了以后省事,subject和内容中设计到title的均会被改为愚人节,马上愚人节了吗,营销方式,代码实现,异常方便修改。
#邮箱内容设置 _content = """\ <html> <style> .title{font-weight:bold;font-size:18px;}</style> <body> <p> <img src="cid:image1"> <br><br> <span class="title">【愚人节】将至,您还没准备礼物?那你一定会过个开心的愚人节的</span> <br> 愚人节就要来啦,礼朵朵给大伙准备了大批量的礼物伴你度过愚人节,具体百度一下【礼朵朵】,赶紧进站选礼物吧~ <br> 选礼物前别忘了先去心愿墙许愿哟,你的愿望可能被礼朵朵看到,可以帮你实现哟,实现的时候别忘了来礼朵朵还愿哈~ <br><br> <span class="title">【礼朵朵】介绍</span> <br> 国人从古至今都有送礼的习俗,送礼作为传统之一,一直流传至今,礼尚往来成为人生必修课。 <br> 【礼朵朵】集合商业送礼和现代送礼搭建礼物导购分享平台【朵朵礼物】,带给老少皆宜的送礼分享体验新体验。 <br> 与此同时,礼朵朵还给大伙准备了礼物攻略【礼物说】,让大家可以对礼物有个更全面的了解~ <br><br> <span class="title">百度搜索【礼朵朵】,开启你的礼物新旅程吧~</span> <br><br> </p> </body> </html> """
营销内容模板,html模式实现邮件的发送,少不了有模板~
#发送邮箱smtp地址 _smtp_address = ['smtp.163.com','smtp.sina.cn','smtp.tom.com','smtp.sohu.com']
smtp地址数组,用于在不同的邮件服务器间切换。
def sendMail(sender,reciver,subject,content,passwd,smtpadd): username=sender password=passwd msg=MIMEMultipart('related') msg['Subject']=subject #html格式 html=content htm = MIMEText(html,'html','utf-8') msg.attach(htm) #构造图片 fp=open(_root_dir+'Image/logo_small.png','rb') msgImage=MIMEImage(fp.read()) fp.close() msgImage.add_header("Content-ID", "<image1>") msg.attach(msgImage) fp2=open(_root_dir+'Image/yurenjie.png','rb') msgImage2=MIMEImage(fp2.read()) fp2.close() msgImage2.add_header('Content-Disposition', 'attachment', filename="愚人节活动海报.jpg") msg.attach(msgImage2) msg['From']=sender msg['To']=reciver #发送邮件 smtp=smtplib.SMTP() smtp.connect(smtpadd) smtp.login(username, password) smtp.sendmail(sender, reciver, msg.as_string()) smtp.quit()
发邮件方法,里面有两个地方需要注意,一个是
msgImage.add_header("Content-ID", "<image1>") msg.attach(msgImage)
将邮件模板中的image1的img标签内容替换成我们想要的图片
第二个
fp2=open(_root_dir+'Image/yurenjie.png','rb') msgImage2=MIMEImage(fp2.read()) fp2.close() msgImage2.add_header('Content-Disposition', 'attachment', filename="愚人节活动海报.jpg")
插入附件,图片是一个海报,说起海报,强烈建议大家使用创客贴这个平台,非常好用。
下面就是发送邮件啦!!!
#发送邮件 smtp=smtplib.SMTP() smtp.connect(smtpadd) smtp.login(username, password) smtp.sendmail(sender, reciver, msg.as_string()) smtp.quit()
通用方法,将文件中的以,分割的内容以数组形式返回
#读取文件中的数据,并将使用,分割的数据变为数组 def readFileToSplit(filepath): file_stream = open(filepath) try: data = file_stream.read() finally: file_stream.close() data_split = data.split(',') return data_split
主方法
1、切割账号
2、切换邮件服务器
3、每发送一封邮件,休息25秒,切换账号,继续发送
4、日志记录
5、错误处理
if __name__=="__main__": content=_content # 接收人的邮箱按照每天2000封来,每天的邮箱都需要更换,文件名最后以日期为准,邮件发送量以日志为准 recivers=readFileToSplit(_root_dir+'Sendmail/mail_test.txt') # 把4个邮箱的账号都获取到,方便下面for循环中使用 account_163=readFileToSplit(_root_dir+'Account/account163') account_sina=readFileToSplit(_root_dir+'Account/accountsina') account_tom = readFileToSplit(_root_dir+'Account/accounttom') account_sohu = readFileToSplit(_root_dir+'Account/accountsohu') # 获取邮件发送模板 # 注意模板之间的切换 #log_file_stream = open(_root_dir+'log', 'w+') logger.info('') logger.info('脚本开始------------------------------------------------------------------') # 统计邮件发送量 send_num = 0 # 统计发送出错量 error_num = 0 # 统计发送失败的邮箱发送账号 send_success_account = [] # 统计发送成功的邮箱发送账号 send_failure_account = [] subject_num = len(_subject) # 最后统计没有发出去的邮箱号,放到下日,继续发送 for i in range(0, len(recivers)): try: sendindex = i - error_num num = i % 30 account = account_163[num].split(':') addindex=i%4 subjectindex = sendindex%subject_num if addindex == 1: account=account_sina[num].split(':') elif addindex == 2: account=account_tom[num].split(':') elif addindex == 3: account=account_sohu[num].split(':') sender=account[0] passwd=account[1] smtpadd = _smtp_address[addindex] #smtpstr=str('163') sendMail(sender, recivers[sendindex], _subject[subjectindex], content, passwd, smtpadd) #print('发送账号', sender, '正在发送') str_success_1 = '发送账号【'+sender+'】正在发送' logger.info(str_success_1) #writeLog(log_file_stream,str_success_1) #print('接收序号', i, recivers[i],'发送成功') str_success_2 = '接受序号【'+str(i)+'】【'+recivers[sendindex]+'】发送成功' #writeLog(log_file_stream,str_success_2) logger.info(str_success_2) logger.info('') #print('') send_num+=1 send_success_account.append(sender) time.sleep(25) except Exception as e: #print('停止于:', i, recivers[i],',发送失败') str_failure_1 = '产生错误于:【'+sender+'】发送失败' #writeLog(log_file_stream,str_failure_1) logger.error(str_failure_1) #print(e) str_failure_2 = str(e) #writeLog(log_file_stream,str_failure_2) logger.error(str_failure_2) logger.info('') error_num+=1 send_failure_account.append(sender) #print('') #break #print('安全抵达底部') #writeLog(log_file_stream,'脚本结束') set(send_success_account) set(send_failure_account) logger.info('邮件总数量【'+str(len(recivers))+'】') logger.info('总计发送邮件数量【'+str(send_num)+'】') logger.info('总计发送错误数量【'+str(error_num)+'】') logger.info('成功邮箱账号集合:'+','.join(send_success_account)) logger.info('失败邮箱账号集合:'+','.join(send_failure_account)) logger.info('脚本结束------------------------------------------------------------------') logger.info('') #log_file_stream.close()
代码就这么多,至于subject邮件主题和模板怎么搞,可以自由发挥哈,可以放在主执行文件中,也可以放到配置文件中,实现可以配置,这里就不再赘述啦
开工
下面就可以开工啦,直接到项目主目录
#python mail_html.py
The above is the detailed content of Teach you a python code example to make an automatic email script. For more information, please follow other related articles on the PHP Chinese website!