室友选修的《机器学习》,结课做业是对8万+的数据进行分析。他向我抱怨,说这么多数据至少得运算半个多小时,还得语法逻辑不出错,否则得重来。
“总不能守着电脑吧,想出去玩,又拿不许程序准确结束时间。”
我想python做为编程界的万金油,几乎不存在它不能染指的地方。因此有了如下基于smtp协议、利用python自带模块email,smtplib实现自动化发送邮件的代码。python
有必要简单了解一下SMTP的概念,能够加深对代码的理解。git
因此什么是SMTP呢?
SMTP是简单邮件传输协议,不过只能传送可打印的7位ASCII码邮件,这样存在过大的局限性。因而后来有了MIME,即通用互联网邮件扩充。MIME在邮件首部中说明了邮件的数据类型(如文本,声音,图像,视像等),且经过MIME邮件能够同时传送多种类型的数据(附件)。github
一个邮件系统应该具备三个主要组成构建。用户代理、邮件服务器,邮件发送协议(SMTP)和邮件读取协议(POP3,又:邮局协议)
编程
SMTP客户端(发送方的邮件服务器)每隔必定时间对邮件缓存扫描,若是发现有邮件,就用25端口与接收方的SMTP服务器创建TCP链接。链接创建后,接收方服务器发出“服务就绪”,SMTP客户端向SMTP服务器发送HELO命令,附上发送方的主机名。SMTP服务器若是有能力接受邮件,就回复“250”(OK),若是服务不可用回复“421”。缓存
略服务器
邮件发送完毕后,SMTP客户发送QUIT命令。SMTP服务器返回“221”(服务关闭),表示赞成释放TCP链接。邮件传输过程结果。app
1. SMTP不使用中间邮件服务器,必定是发送方服务器到接收方服务器
2. 为何要经过邮件服务器而不是直接发送方用户代理–>接收方用户代理呢?缘由很简单,被人给你发送邮件的时候你并不必定在机器学习
一个邮件分为信封和内容两大部分,内容包含首部、主体。
1. 首部(header),有规定格式,比较重要有如下:
“To” 接收方邮件地址
“Subject” 邮件主题
“From” 发送方邮件地址
2. 主体(body),容许用户自由撰写学习
attachment
,即以附件形式下载);disposition-parm表示文件保存的默认名有了以上对SMTP知识简单的梳理以后,就能够很容易理解后面的代码。而这里我是经过登录本身的邮箱来实现发送邮件,这样作的目的是:若是不登录本身的邮箱,发送出去的邮件很容易被误认为垃圾邮件,或是被屏蔽,或是在垃圾箱,接收方不能及时收取。ui
python内置两个模块,email和smtplib,前者负责构建一封邮件,后者实现发送
基于python建立一封邮件,使用的是email模块,我会用不严谨、但尽量生动的语言来解释对象的内置方法
from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText aLetter = MIMEMultipart() #实例化“一个包裹” # attach(),往包裹里面放东西 # MIMEText()能够看作一封信,第一个参数表示内容,第二个表示类型,第三个表示编码格式 aLetter.attach(MIMEText("hello,what are you doing?", "plain", "utf-8")) # 在“包裹”上写上发给谁(to),发的什么(subject),谁发的(from) aLetter["To"] = "xxxxx@qq.com" aLetter["Subject"] = "Make A Friend" aLetter["From"] = "myemail@qq.com" # 实例化一封附加信 attachment = MIMEText("i miss you,and you?", "plain", "utf-8") # 说明邮件数据的主题类型和子类型 attachment["Content-Type"] = "text/plain" # 以附件形式下载,默认文件名为happy.txt attachment["Content-Disposition"] = "attachment;filename=happy.txt" # 将附加信丢入包裹中 aLetter.attach(attachment) print(aLetter) # 打印输出效果
因而有了下面一个“包裹”
有了包裹,就须要邮寄出去,这里须要用到smtplib模块来发送邮件,流程以下:
# 实例化一个smtp对象 smtp = smtplib.SMTP_SSL() # 链接邮件服务器 smtp.connect("smtp.qq.com") # 登录本身的邮箱 smtp.login("578******@qq.com", "htn******cga") # 发送邮件 smtp.sendmail("578******@qq.com", "gu******995@163.com", aLetter.as_string()) # 退出链接 smtp.quit()
如此就是一个完整的发送邮件的过程
为了更高效的利用代码,为了使代码具备更好的扩展性,利用面向对象的思想来封装代码天然是不可少的。
首先我写了一个AutoEmail的父类,其下有6个方法,依次对应:登录信息,发送信息,生成邮件,生成附件,发送邮件,选择服务器。
因为网易163邮箱和QQ邮箱链接的服务器不一样,前者“smtp.163.com”,后者“smtp.qq.com”,且网易针对smtplib.SMTP()实例化对象,而QQ邮箱须要针对smtp.SMTP_SSL()
固然,为了对用户更友好,这里我写了两个派生类来继承AutoEmail。
父类的choose_server()方法,经过区分实例化对象的类名,来提供相对应的方法
获取实例化对象的类名:__class__.__name__
若是是网易邮箱
若是是QQ邮箱
代码中的邮箱密码,不是邮箱的真实代码,而是受权密码。
完整代码请查看GitHub