python-发送邮件与定时
1.发送邮件
先来模仿一下平时我们发邮件时计算机的操作
我们的代码逻辑也会按照上图来进行,并且在其中用到两个库——smtplib
和email
。
以qq邮箱为例,先来看第0步:连接服务器。
连接服务器需要用到smtplib
库。为什么叫这个名字呢?其实,SMTP
代表简单邮件传输协议,相当于一种计算机之间发邮件的约定。
好,来看下具体怎么用smtplib
库来连接服务器:
import smtplib #smtplib是python的一个内置库,所以不需要用pip安装 mailhost='smtp.qq.com' #把qq邮箱的服务器地址赋值到变量mailhost上,地址需要是字符串的格式。 qqmail = smtplib.SMTP() #实例化一个smtplib模块里的SMTP类的对象,这样就可以SMTP对象的方法和属性了 qqmail.connect(mailhost,25) #连接服务器,第一个参数是服务器地址,第二个参数是SMTP端口号。
解释一下:第1行代码是引入库,第2行代码是qq邮箱的服务器地址,这个地址是可以通过搜索引擎查到的。
第7行代码是用SMTP对象的connect()
方法连接服务器,第一个参数是获取到的服务器地址,第二个参数是SMTP端口号——25
。
端口号的选择不是唯一的,但是25
是一个最简单、最基础的端口号,所以我们填25
。
连接服务器就讲完了,马上来看第1和第2步:通过账号和密码登录邮箱;填写收件人。
来看登录邮箱的代码(第11行为新增代码):
import smtplib #smtplib是python的一个内置库,所以不需要用pip安装 mailhost='smtp.qq.com' #把qq邮箱的服务器地址赋值到变量mailhost上 qqmail = smtplib.SMTP() #实例化一个smtplib模块里的SMTP类的对象,这样就可以SMTP对象的方法和属性了 qqmail.connect(mailhost,25) #连接服务器,第一个参数是服务器地址,第二个参数是SMTP端口号。 #以上,皆为连接服务器的代码 account = input('请输入你的邮箱:') #获取邮箱账号 password = input('请输入你的密码:') #获取邮箱密码 qqmail.login(account,password) #登录邮箱,第一个参数为邮箱账号,第二个参数为邮箱密码 receiver=input('请输入收件人的邮箱:') #获取收件人的邮箱
解释一下从11行新增的代码:第11行是用input()
获取邮箱账号。第12行是用input()
获取邮箱密码,但注意了,这里可不是你平时登录邮箱的密码!
这个密码需要我们去到这里获取:请打开https://mail.qq.com/,登录你的邮箱。然后点击位于顶部的【设置】按钮,选择【账户设置】,然后下拉到这个位置。
就像上面的一样,把首个SMTP服务开启。这时,QQ邮箱会提供给你一个授权码,注意保护好你的授权码:
接下来,在你使用SMTP服务登录邮箱时,就可以输入这个授权码作为密码登录了。
继续看第3步和第4步:填写主题和撰写正文,在这里需要用到email
库。
1 from email.mime.text import MIMEText 2 from email.header import Header 3 #引入Header和MIMEText模块 4 content=input('请输入邮件正文:') 5 #输入你的邮件正文 6 message = MIMEText(content, 'plain', 'utf-8') 7 #实例化一个MIMEText邮件对象,该对象需要写进三个参数,分别是邮件正文,文本格式和编码. 8 subject = input('请输入你的邮件主题:') 9 #用input()获取邮件主题 10 message['Subject'] = Header(subject, 'utf-8') 11 #在等号的右边,是实例化了一个Header邮件头对象,该对象需要写入两个参数,分别是邮件主题和编码,然后赋值给等号左边的变量message['Subject']。
解释一下:第1行和第2行代码是引入了email
库中的MIMEText
模块和Header
模块。
第4行代码是用input()
函数获取邮件正文,第6行代码是实例化一个MIMEText
的邮件对象,这样我们就构造了一个纯文本邮件了。
这个MIMEText
对象有三个参数,一个是邮件正文;另一个是文本格式,一般设置为plain
纯文本格式;最后一个是编码,设置为utf-8
,因为utf-8是最流行的万国码。
继续看第8行代码,是用input()
函数获取邮件主题,第10行代码比较重要,我们仔细讲解一下:message['Subject'] = Header(subject, 'utf-8')
等号右边是实例化了一个Header
邮件头对象,该对象需要写入两个参数,分别是邮件主题和编码。
等号左边的message['Subject']
的变量是一个a['b']
的代码形式,它长得特别像字典根据键取值的表达,但是这里的message
是一个MIMEText
类的对象,并不是一个字典,那message['Subject']
是什么意思呢?
其实,字典和类在结构上,有相似之处。请看下图:
需要注意的是,不是每一个类都可以这样访问其属性的,之所以能这样访问是因为这个MIMEText
的类实现了这个功能。
所以,message['Subject'] = Header(subject, 'utf-8')
就是在为message['Subject']
这个属性赋值。
1 import smtplib 2 #smtplib是python的一个内置库,所以不需要用pip安装 3 mailhost='smtp.qq.com' 4 #把qq邮箱的服务器地址赋值到变量mailhost上 5 qqmail = smtplib.SMTP() 6 #实例化一个smtplib模块里的SMTP类的对象,这样就可以SMTP对象的方法和属性了 7 qqmail.connect(mailhost,25) 8 #连接服务器,第一个参数是服务器地址,第二个参数是SMTP端口号。 9 #以上,皆为连接服务器的代码 10 11 account = input('请输入你的邮箱:') 12 #获取邮箱账号 13 password = input('请输入你的密码:') 14 #获取邮箱密码 15 qqmail.login(account,password) 16 #登录邮箱,第一个参数为邮箱账号,第二个参数为邮箱密码 17 18 receiver=input('请输入收件人的邮箱:') 19 #获取收件人的邮箱 20 21 from email.mime.text import MIMEText 22 from email.header import Header 23 #引入Header和MIMEText模块 24 content=input('请输入邮件正文:') 25 #输入你的邮件正文 26 message = MIMEText(content, 'plain', 'utf-8') 27 #实例化一个MIMEText邮件对象,该对象需要写进三个参数,分别是邮件正文,文本格式和编码. 28 subject = input('请输入你的邮件主题:') 29 #用input()获取邮件主题 30 message['Subject'] = Header(subject, 'utf-8') 31 #在等号的右边,是实例化了一个Header邮件头对象,该对象需要写入两个参数,分别是邮件主题和编码,然后赋值给等号左边的变量message['Subject']。 32 33 qqmail.sendmail(sender, receiver, message.as_string()) 34 #发送邮件,调用了sendmail()方法,写入三个参数,分别是发件人,收件人,和字符串格式的正文。 35 qqmail.quit() 36 #退出邮箱
解释一下:第33行代码的意思是调用sendmail()
发送邮件,括号里面有三个参数,第0个是发件人的邮箱地址,第1个是收件人的邮箱地址,第2个是正文,但必须是字符串格式,所以用as_string()
函数转换了一下。
但是我们希望发送成功后能显示“邮件发送成功”,失败的时候能提示我们“邮件发送
1 try: 2 qqmail.sendmail(sender, receiver, message.as_string()) 3 print ('邮件发送成功') 4 except: 5 print ('邮件发送失败') 6 qqmail.quit()
失败”,可以使用try
语句来实现。
2.定时
关于时间,其实Python有两个内置的标准库——time
和datetime
(我们在基础课也学过time.sleep()
)。
但在这里,我们不准备完全依靠标准库来实现,而准备选取第三方库——schedule
。
原因在于:标准库一般意味着最原始最基础的功能,第三方库很多是去调用标准库中封装好了的操作函数。比如schedule
,就是用time
和datetime
来实现的。
而对于我们需要的定时功能,time
和datetime
当然能实现,但操作逻辑会相对复杂;而schedule
就是可以直接解决定时功能,代码比较简单,这是我们选择schedule
的原因。
马上来看代码,官方文档上的代码也很简洁,你可以先尝试着自己阅读一下,思考后点击enter继续:
1 import schedule 2 import time 3 #引入schedule和time 4 5 def job(): 6 print("I'm working...") 7 #定义一个叫job的函数,函数的功能是打印'I'm working...' 8 9 schedule.every(10).minutes.do(job) #部署每10分钟执行一次job()函数的任务 10 schedule.every().hour.do(job) #部署每×小时执行一次job()函数的任务 11 schedule.every().day.at("10:30").do(job) #部署在每天的10:30执行job()函数的任务 12 schedule.every().monday.do(job) #部署每个星期一执行job()函数的任务 13 schedule.every().wednesday.at("13:15").do(job)#部署每周三的13:15执行函数的任务 14 15 while True: 16 schedule.run_pending() 17 time.sleep(1) 18 #13-15都是检查部署的情况,如果任务准备就绪,就开始执行任务。
第1行和第2行,是引入schedule
和time
。
第5行和第6行,是定义了一个叫job()
的函数,调用这个函数时,函数会打印I'm working...
。
第9行-13行都是相关的时间设置,你可以根据自己的需要来确定。
第15-17行是一个while
循环,是去检查上面的任务部署情况,如果任务已经准备就绪,就去启动执行。其中,第15行的time.sleep(1)
是让程序按秒来检查,如果检查太快,会浪费计算机的资源。
为了展示一下schedule
的作用,我们看下面这段代码:是每两秒就运行job()
函数。
import schedule import time #引入schedule和time模块 def job(): print("I'm working...") #定义一个叫job的函数,函数的功能是打印'I'm working...' schedule.every(2).seconds.do(job) #每2s执行一次job()函数 while True: schedule.run_pending() time.sleep(1)