Python3利用SMTP協(xié)議發(fā)送E-mail電子郵件的方法
前言
本文主要給大家介紹了關(guān)于Python3用SMTP協(xié)議發(fā)送電子郵件的相關(guān)內(nèi)容,在介紹如何使用python程序向指定郵箱發(fā)送郵件之前,我們需要先介紹一下有關(guān)電子郵件的相關(guān)知識。
Email的歷史比Web還要久遠,直到現(xiàn)在,Email也是互聯(lián)網(wǎng)上應(yīng)用非常廣泛的服務(wù)。
幾乎所有的編程語言都支持發(fā)送和接收電子郵件,但是,先等等,在我們開始編寫代碼之前,有必要搞清楚電子郵件是如何在互聯(lián)網(wǎng)上運作的。
假設(shè)我們自己的電子郵件地址是me@163.com,對方的電子郵件地址是friend@sina.com,現(xiàn)在我們用Outlook或者Foxmail之類的軟件寫好郵件,填上對方的Email地址,點“發(fā)送”,電子郵件就發(fā)出去了。這些電子郵件軟件被稱為MUA:Mail User Agent——郵件用戶代理。
Email從MUA發(fā)出去,不是直接到達對方電腦,而是發(fā)到MTA:Mail Transfer Agent——郵件傳輸代理,就是那些Email服務(wù)提供商,比如網(wǎng)易、新浪等等。由于我們自己的電子郵件是163.com,所以,Email首先被投遞到網(wǎng)易提供的MTA,再由網(wǎng)易的MTA發(fā)到對方服務(wù)商,也就是新浪的MTA。這個過程中間可能還會經(jīng)過別的MTA,但是我們不關(guān)心具體路線,我們只關(guān)心速度。
Email到達新浪的MTA后,由于對方使用的是@sina.com的郵箱,因此,新浪的MTA會把Email投遞到郵件的最終目的地MDA:Mail Delivery Agent——郵件投遞代理。Email到達MDA后,就靜靜地躺在新浪的某個服務(wù)器上,存放在某個文件或特殊的數(shù)據(jù)庫里,我們將這個長期保存郵件的地方稱之為電子郵箱。對方要取到郵件,必須通過MUA從MDA上把郵件取到自己的電腦上。
所以,一封電子郵件的旅程就是:
發(fā)件人 -> MUA -> MTA -> MTA -> 若干個MTA -> MDA <- MUA <- 收件人
有了上述基本概念,要編寫程序來發(fā)送和接收郵件,本質(zhì)上就是:
1.編寫MUA把郵件發(fā)到MTA。
2.編寫MUA從MDA上收郵件。
發(fā)郵件時,MUA和MTA使用的協(xié)議就是SMTP:Simple Mail Transfer Protocol,后面的MTA到另一個MTA也是用SMTP協(xié)議。
收郵件時,MUA和MDA使用的協(xié)議有兩種:POP:Post Office Protocol,目前版本是3,俗稱POP3;IMAP:Internet Message Access Protocol,目前版本是4,優(yōu)點是不但能取郵件,還可以直接操作MDA上存儲的郵件,比如從收件箱移到垃圾箱,等等。
郵件客戶端軟件在發(fā)郵件時,會讓你先配置SMTP服務(wù)器,也就是你要發(fā)到哪個MTA上。假設(shè)你正在使用163的郵箱,你就不能直接發(fā)到新浪的MTA上,因為它只服務(wù)新浪的用戶,所以,你得填163提供的SMTP服務(wù)器地址:smtp.163.com,為了證明你是163的用戶,SMTP服務(wù)器還要求你填寫郵箱地址和郵箱口令,這樣,MUA才能正常地把Email通過SMTP協(xié)議發(fā)送到MTA。
類似的,從MDA收郵件時,MDA服務(wù)器也要求驗證你的郵箱口令,確保不會有人冒充你收取你的郵件,所以,Outlook之類的郵件客戶端會要求你填寫POP3或IMAP服務(wù)器地址、郵箱地址和口令,這樣,MUA才能順利地通過POP或IMAP協(xié)議從MDA取到郵件。
最后特別注意:目前大多數(shù)郵件服務(wù)商都需要手動打開SMTP發(fā)信和POP收信的功能,否則只允許在網(wǎng)頁登錄:
比如QQ郵箱
接下來,我們開始我們的正題,如何通過python發(fā)送電子郵件。
--------------------------------------------------------------------------------
發(fā)送簡單文本郵件
SMTP是發(fā)送郵件的協(xié)議,Python內(nèi)置對SMTP的支持,可以發(fā)送純文本郵件、HTML郵件以及帶附件的郵件。
Python對SMTP支持有smtplib和email兩個模塊,email負責構(gòu)造郵件,smtplib負責發(fā)送郵件。
首先,我們來構(gòu)造一個最簡單的純文本郵件:
from email.mime.text import MIMEText msg = MIMEText('hello, this is axin...', 'plain', 'utf-8')
注意:到構(gòu)造MIMEText對象時,第一個參數(shù)就是郵件正文,第二個參數(shù)是MIME的subtype,傳入'plain'表示純文本,最終的MIME就是'text/plain',最后一定要用utf-8編碼保證多語言兼容性。
我們光有了正文內(nèi)容還不可以,我們還需要給我們要發(fā)送的郵件添加頭部信息。頭部信息中包含發(fā)送者和接收者以及郵件主題等信息。
msg = MIMEText('hello, this is axin...', 'plain', 'utf-8') #郵件正文 msg['From'] = _format_addr('阿鑫 <%s>' % from_addr) #郵件頭部,發(fā)送者信息 msg['To'] = _format_addr('aa <%s>' % to_addr) #接收者信息 msg['Subject'] = Header('test', 'utf-8').encode() #郵件主題
構(gòu)造完我們要發(fā)送的信息后,我們只需要調(diào)用python對應(yīng)的函數(shù),通過SMTP發(fā)出去:
server = smtplib.SMTP(smtp_server, 25) #SMTP協(xié)議默認端口是25 server.set_debuglevel(1) #打印出和SMTP服務(wù)器交互的所有信息 server.login(from_addr, password) #登錄SMTP服務(wù)器 server.sendmail(from_addr, [to_addr], msg.as_string()) #發(fā)送郵件 server.quit()
我們用set_debuglevel(1)
就可以打印出和SMTP服務(wù)器交互的所有信息。SMTP協(xié)議就是簡單的文本命令和響應(yīng)。login()方法用來登錄SMTP服務(wù)器,sendmail()
方法就是發(fā)郵件,由于可以一次發(fā)給多個人,所以傳入一個list,郵件正文是一個str,as_string()
把MIMEText對象變成str。
完整代碼示例如下:
from email import encoders from email.header import Header from email.mime.text import MIMEText from email.utils import parseaddr, formataddr import smtplib def _format_addr(s): #格式化一個郵件地址 name, addr = parseaddr(s) return formataddr((Header(name, 'utf-8').encode(), addr)) from_addr = 'fengxinlinux@sina.com' #發(fā)送者郵箱地址 password = '******' #發(fā)送者郵箱密碼,不告訴你密碼=。= to_addr = '903087053@qq.com' #接收者郵箱地址 smtp_server = 'smtp.sina.com' #發(fā)送者所在的郵箱供應(yīng)商的MTA地址 #from_addr = input('From: ') #password = input('Password: ') #to_addr = input('To: ') #smtp_server = input('SMTP server: ') msg = MIMEText('hello, this is axin...', 'plain', 'utf-8') #郵件正文 msg['From'] = _format_addr('阿鑫 <%s>' % from_addr) #郵件頭部,發(fā)送者信息 msg['To'] = _format_addr('axin <%s>' % to_addr) #接收者信息 msg['Subject'] = Header('test', 'utf-8').encode() #郵件主題 server = smtplib.SMTP(smtp_server, 25) # SMTP協(xié)議默認端口是25 server.set_debuglevel(1) #打印出和SMTP服務(wù)器交互的所有信息 server.login(from_addr, password) #登錄SMTP服務(wù)器 server.sendmail(from_addr, [to_addr], msg.as_string()) #發(fā)送郵件 server.quit() 1
運行程序,我們會發(fā)現(xiàn)我測試的郵箱中收到了一封新的郵件。
我們會發(fā)現(xiàn),其他的信息都一樣,但是收件人的信息不是我們程序里填寫的axin。
因為很多郵件服務(wù)商在顯示郵件時,會把收件人名字自動替換為用戶注冊的名字,但是其他收件人名字的顯示不受影響。
我在測試時,有時候發(fā)送的郵件會被郵件服務(wù)商判定為垃圾郵件,直接被放到垃圾箱中了。。。至于什么情況會被認定為垃圾郵件,我也摸不到頭緒。。
發(fā)送帶附件的郵件
上面我們介紹了如何發(fā)送文本郵件,有了上面的知識后,發(fā)送帶有附件的郵件其實也非常的簡單。
帶附件的郵件可以看做包含若干部分的郵件:文本和各個附件本身,所以,可以構(gòu)造一個MIMEMultipart對象代表郵件本身,然后往里面加上一個MIMEText作為郵件正文,再繼續(xù)往里面加上表示附件的MIMEBase對象即可:
# 郵件對象: msg= MIMEMultipart() msg['From'] = _format_addr('阿鑫 <%s>' % from_addr) #郵件頭部,發(fā)送者信息 msg['To'] = _format_addr('axin <%s>' % to_addr) #接收者信息 msg['Subject'] = Header('test', 'utf-8').encode() #郵件主題 # 郵件正文是MIMEText: msg.attach(MIMEText('hello, this is axin...', 'plain', 'utf-8')) # 添加附件就是加上一個MIMEBase,從本地讀取一個圖片: with open('/home/fengxin/圖片/11.jpg','rb') as fhandle: mime = MIMEBase('image','jpeg',filename='11.jpg') mime.add_header('Content-Disposition', 'attachment', filename='11.jpg') mime.add_header('Content-ID', '<0>') mime.add_header('X-Attachment-Id', '0') # 把附件的內(nèi)容讀進來: mime.set_payload(fhandle.read()) # 用Base64編碼: encoders.encode_base64(mime) # 添加到MIMEMultipart: msg.attach(mime)
然后,按正常發(fā)送流程把msg(注意類型已變?yōu)镸IMEMultipart)發(fā)送出去,就可以收到帶附件的郵件。
完整代碼示例如下:
from email import encoders from email.header import Header from email.mime.text import MIMEText from email.utils import parseaddr, formataddr from email.mime.multipart import MIMEMultipart from email.mime.base import MIMEBase import smtplib def _format_addr(s): #格式化一個郵件地址 name, addr = parseaddr(s) return formataddr((Header(name, 'utf-8').encode(), addr)) from_addr = '你的郵箱地址' #發(fā)送者郵箱地址 password = '你的郵箱密碼' #發(fā)送者郵箱密碼 to_addr = '903087053@qq.com' #接收者郵箱地址 smtp_server = 'smtp.sina.com' #發(fā)送者所在的郵箱供應(yīng)商的MTA地址 #from_addr = input('From: ') #password = input('Password: ') #to_addr = input('To: ') #smtp_server = input('SMTP server: ') msg= MIMEMultipart() msg['From'] = _format_addr('阿鑫 <%s>' % from_addr) #郵件頭部,發(fā)送者信息 msg['To'] = _format_addr('axin <%s>' % to_addr) #接收者信息 msg['Subject'] = Header('test', 'utf-8').encode() #郵件主題 msg.attach(MIMEText('hello, this is axin...', 'plain', 'utf-8')) with open('/home/fengxin/圖片/11.jpg','rb') as fhandle: mime = MIMEBase('image','jpeg',filename='11.jpg') mime.add_header('Content-Disposition', 'attachment', filename='11.jpg') mime.add_header('Content-ID', '<0>') mime.add_header('X-Attachment-Id', '0') # 把附件的內(nèi)容讀進來: mime.set_payload(fhandle.read()) # 用Base64編碼: encoders.encode_base64(mime) # 添加到MIMEMultipart: msg.attach(mime) server = smtplib.SMTP(smtp_server, 25) # SMTP協(xié)議默認端口是25 server.set_debuglevel(1) #打印出和SMTP服務(wù)器交互的所有信息 server.login(from_addr, password) #登錄SMTP服務(wù)器 server.sendmail(from_addr, [to_addr], msg.as_string()) #發(fā)送郵件 server.quit() 1
運行后。測試郵箱正確收到郵件,如圖:
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
pandas缺失值np.nan, np.isnan, None, pd.isnull,&n
本文主要介紹了pandas缺失值np.nan, np.isnan, None, pd.isnull, pd.isna2024-04-04Python3+Appium安裝及Appium模擬微信登錄方法詳解
這篇文章主要介紹了Python3+Appium安裝及使用方法詳解,需要的朋友可以參考下2021-02-02Python的PIL庫中g(shù)etpixel方法的使用
這篇文章主要介紹了Python的PIL庫中g(shù)etpixel方法的使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-04-04利用 Python 實現(xiàn)隨機相對強弱指數(shù) StochRSI
隨機相對強弱指數(shù)簡稱為StochRSI,是一種技術(shù)分析指標,用于確定資產(chǎn)是否處于超買或超賣狀態(tài),也用于確定當前市場的態(tài)勢。本篇文章小編九來為大家介紹隨機相對強弱指數(shù)簡稱為StochRSI,需要的朋友可以參考下面文章的具體內(nèi)容2021-09-09Django怎么在admin后臺注冊數(shù)據(jù)庫表
這篇文章主要介紹了Django怎么在admin后臺注冊數(shù)據(jù)庫表,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-11-11