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)