概要
我們都知道SMTP(簡單郵件傳輸協議),是一組用於從原地址到目的地址傳輸郵件的規范,通過它來控制郵件的中轉方式。SMTP規定電子郵件應該如何格式化、如何加密,以及如何在郵件服務器之間傳遞。SMTP服務器就是通過遵循SMTP協議的發送郵件服務器。
如果你使用過郵件客戶端,比如Foxmail,outlook等,那么你應該了解SMTP服務器和端口號,除了服務器和端口,我們還需要進行其他配置,默認情況下郵件服務提供商是不允許我們使用程序進行郵件發送的,如果想要使用程序發送電子郵件,就需要我們手動開啟SMTP服務,並獲取一個專用的授權碼(用於登陸)。 -- 需要自行去了解所用郵箱的授權碼獲取方式
使用smtplib和email模塊發送郵件
得到郵箱的授權碼就可以使用Python代碼發送電子郵件了。Python標准庫有多個與郵件相關的模塊,其中smtplib負責發送郵件,email模塊用來構造郵件和解析郵件內容。
smtplib模塊
stmplib發送郵件大概分為以下幾個步驟:
- 連接到SMTP服務器
- 發送SMTP的“Hello”消息
- 登陸到SMTP服務器
- 發送電子郵件
- 關閉SMTP服務器的連接
對於簡單的郵件,smtplib的使用是非常簡單的,下面是實例
# 導入smtplib模塊 import smtplib # 創建SMTP對象,括號內為SMTP服務器地址及端口號 smtp = smtplib.SMTP('smtp.qq.com',25) # 向SMTP服務器打一個招呼,查看連接狀態 smtp.ehlo() (250, b'smtp.qq.com\nPIPELINING\nSIZE 73400320\nSTARTTLS\nAUTH LOGIN PLAIN\nAUTH=LOGIN\nMAILCOMPRESS\n8BITMIME') # 連接使用TLS加密(然后就可以傳遞敏感信息了),否則無法使用login方法登陸會提示SMTPServerDisconnected 異常 smtp.starttls() (220, b'Ready to start TLS') # 登陸郵箱,傳遞的是用戶名密碼 smtp.login('287990400@qq.com','oiifptyw......') # 授權碼 (235, b'Authentication successful') # 發送郵件 smtp.sendmail('287990400@qq.com','932911203@qq.com','Subject:this is title\n this is content') {} # 郵件發送完畢后關閉鏈接 smtp.quit() (221, b'Bye')
PS:sendmail的參數為發件人,收件人,郵件內容
注意:可以在創建加密鏈接之前使用smtp.set_debuglevel(1),來顯示與SMTP服務器交互的相關信息
查看發送的郵件會發送,有兩個問題,一是收件人欄為空,二是郵件內容缺失,這是因為郵件主題、如何顯示發件人、收件人等信息並不是通過SMTP協議發給MTA,而是包含在發給MTA的文本中的,所以,我們必須把From
、To
和Subject
添加到email模塊中的MIMEText
中,才是一封完整的郵件。(MTA可以理解為郵件代理服務器)。
smtplib模塊結合email模塊
使用email模塊構建一個郵件對象(Message),email模塊中支持很多郵件對象
- MIMEText:表示一個純文本的郵件 * 常用
- MIMEImage:表示一個作為附件的圖片
- MIMEMultipart:用於把多個對象組合起來
其中還有諸如其他的類:MIMEBase、MIMEAudio等。
MIMEText對象的主要參數是:MIMEText(_text, _subtype='plain', _charset=None),其中:
- _text:表示郵件內容
- _subtype:表示郵件內容的類型,默認為plain(純文本),還可以設置為html,表示正文是html文件(會渲染HTML標簽)
- _charset:表示郵件編碼,默認情況下使用ascii編碼
下面是一個發送純文本郵件的例子:
#!/usr/bin/env python3 import smtplib from email.mime.text import MIMEText SMTP_SERVER = 'smtp.qq.com' SMTP_PORT = 25 def send_mail(user,passwd,to,subject,text): msg = MIMEText(text) msg['From'] = user # 構建msg對象的發件人 msg['to'] = to # 構建msg對象的收件人 msg['Subject'] = subject # 構建msg對象的郵件正文 smtp_server = smtplib.SMTP(SMTP_SERVER,SMTP_PORT) print('Connecting To mail Server') try: smtp_server.ehlo() print('Starting Encrypted Session.') smtp_server.starttls() smtp_server.ehlo() print('Loggin Into Mail Server.') smtp_server.login(user,passwd) print('Send mail.') smtp_server.sendmail(user,to,msg.as_string()) # 利用msg的as_string()方法轉換成字符串 except Exception as err: print('Sending Mail Failed:{0}'.format(err)) finally: smtp_server.quit() def main(): send_mail('287990400@qq.com','vgdw...ucafc','932911203@qq.com','Important','Text Message from dahlhin') if __name__ == '__main__': main()
PS:利用msg對象,我們可以構建郵件的header,通過添加header信息,給郵件增加subject等參數,達到補全郵件信息的目的。msg的header添加方式和使用字典的方式相同。
帶附件的郵件
前面說明了發送純文本郵件的方法,在使用郵件發送帶附件(圖片)的郵件時,需要使用MIMEMultipart對象,並把MIMEImage對象添加。
import smtplib import os from email.mime.image import MIMEImage from email.mime.multipart import MIMEMultipart from email.mime.application import MIMEApplication SMTP_SERVER = 'smtp.qq.com' SMTP_PORT = 25 def send_mail(user, passwd, to, subject, text): msg = MIMEMultipart(text) msg['From'] = user # 構建msg對象的發件人 msg['to'] = to # 構建msg對象的收件人 msg['Subject'] = subject # 構建msg對象的郵件正文 msg.preamble = subject smtp_server = smtplib.SMTP(SMTP_SERVER, SMTP_PORT) print('Connecting To mail Server') try: smtp_server.ehlo() print('Starting Encrypted Session.') smtp_server.starttls() smtp_server.ehlo() print('Loggin Into Mail Server.') smtp_server.login(user, passwd) # 添加圖片附件 url = r'C:\Users\Are you SuperMan\Pictures\Saved Pictures' for img in os.listdir(url): jpgpart = MIMEImage(open(os.path.join(url,img),'rb').read(),'png') jpgpart.add_header('Content-Disposition', 'attachment', filename=img) # 用於告知瀏覽器下載附件文件時的名稱 msg.attach(jpgpart) print('Send mail.') smtp_server.sendmail(user, to, msg.as_string()) # 利用msg的as_string()方法進行轉換 except Exception as err: print('Sending Mail Failed:{0}'.format(err)) finally: smtp_server.quit() def main(): send_mail('287990400@qq.com', 'jwxpwixnpruwcabj', '932911203@qq.com', 'Important2', 'Text Message from dahlhin') if __name__ == '__main__': main()
使用yagmail發送郵件
Python的標准庫smtplib和email,相對來說還是比較復雜的,因此許多開源項目提供了更加易用的接口來發送郵件。比如yagmail就是一個使用比較廣泛的開源項目,它依舊使用smtplib和email模塊,但是相對於直接使用smtplib和email模塊,它提供了更加Pythonic的接口,並具有更好的易用性。
由於yagmail屬於第三方庫,在使用前需要先行安裝
pip3 install yagmail
下面使用yagmail發送一封簡單的郵件
server = yagmail.SMTP(user='287990400@qq.com',password='vgdwgrziieducafc',host='smtp.qq.com',port=25,smtp_starttls=True,smtp_ssl=False) content = ['this is my first mail','used for yagmail'] server.send('932911203@qq.com','IMPORTANT',content) # 對方郵箱,主題,郵件內容
如果要攜帶附件那么只需要在send后面添加即可
server = yagmail.SMTP(user='287990400@qq.com',password='vgdwgrziieducafc',host='smtp.qq.com',port=25,smtp_starttls=True,smtp_ssl=False) content = ['this is my first mail','used for yagmail'] server.send('932911203@qq.com','Images',content,['/Users/DahlHin/Desktop/image.jpg'])
再也沒有這么好用的第三方郵件庫了