1. 程式人生 > >聰哥哥教你學Python之電子郵件

聰哥哥教你學Python之電子郵件

聰哥哥今天主要講的是如何用Python實現電子郵件傳送。這個電子郵件傳送的應用場景有很多,比如註冊使用者發郵件驗證,監控伺服器郵件告警等等。

引用廖雪峰先生的說法:

Email的歷史比Web還要久遠,直到現在,Email也是網際網路上應用非常廣泛的服務。

幾乎所有的程式語言都支援傳送和接收電子郵件,但是,先等等,在我們開始編寫程式碼之前,有必要搞清楚電子郵件是如何在網際網路上運作的。

我們來看看傳統郵件是如何運作的。假設你現在在北京,要給一個香港的朋友發一封信,怎麼做呢?

首先你得寫好信,裝進信封,寫上地址,貼上郵票,然後就近找個郵局,把信仍進去。

信件會從就近的小郵局轉運到大郵局,再從大郵局往別的城市發,比如先發到天津,再走海運到達香港,也可能走京九線到香港,但是你不用關心具體路線,你只需要知道一件事,就是信件走得很慢,至少要幾天時間。

信件到達香港的某個郵局,也不會直接送到朋友的家裡,因為郵局的叔叔是很聰明的,他怕你的朋友不在家,一趟一趟地白跑,所以,信件會投遞到你的朋友的郵箱裡,郵箱可能在公寓的一層,或者家門口,直到你的朋友回家的時候檢查郵箱,發現信件後,就可以取到郵件了。

電子郵件的流程基本上也是按上面的方式運作的,只不過速度不是按天算,而是按秒算。

現在我們回到電子郵件,假設我們自己的電子郵件地址是[email protected],對方的電子郵件地址是[email protected](注意地址都是虛構的哈),現在我們用Outlook或者Foxmail之類的軟體寫好郵件,填上對方的Email地址,點“傳送”,電子郵件就發出去了。這些電子郵件軟體被稱為MUA

:Mail User Agent——郵件使用者代理。

Email從MUA發出去,不是直接到達對方電腦,而是發到MTA:Mail Transfer Agent——郵件傳輸代理,就是那些Email服務提供商,比如網易、新浪等等。由於我們自己的電子郵件是163.com,所以,Email首先被投遞到網易提供的MTA,再由網易的MTA發到對方服務商,也就是新浪的MTA。這個過程中間可能還會經過別的MTA,但是我們不關心具體路線,我們只關心速度。

Email到達新浪的MTA後,由於對方使用的是@sina.com的郵箱,因此,新浪的MTA會把Email投遞到郵件的最終目的地MDA:Mail Delivery Agent——郵件投遞代理。Email到達MDA後,就靜靜地躺在新浪的某個伺服器上,存放在某個檔案或特殊的資料庫裡,我們將這個長期儲存郵件的地方稱之為電子郵箱。

同普通郵件類似,Email不會直接到達對方的電腦,因為對方電腦不一定開機,開機也不一定聯網。對方要取到郵件,必須通過MUA從MDA上把郵件取到自己的電腦上。

所以,一封電子郵件的旅程就是:

發件人 -> MUA -> MTA -> MTA -> 若干個MTA -> MDA <- MUA <- 收件人

 

有了上述基本概念,要編寫程式來發送和接收郵件,本質上就是:

  1. 編寫MUA把郵件發到MTA;

  2. 編寫MUA從MDA上收郵件。

發郵件時,MUA和MTA使用的協議就是SMTP:Simple Mail Transfer Protocol,後面的MTA到另一個MTA也是用SMTP協議。

收郵件時,MUA和MDA使用的協議有兩種:POP:Post Office Protocol,目前版本是3,俗稱POP3;IMAP:Internet Message Access Protocol,目前版本是4,優點是不但能取郵件,還可以直接操作MDA上儲存的郵件,比如從收件箱移到垃圾箱,等等。

郵件客戶端軟體在發郵件時,會讓你先配置SMTP伺服器,也就是你要發到哪個MTA上。假設你正在使用163的郵箱,你就不能直接發到新浪的MTA上,因為它只服務新浪的使用者,所以,你得填163提供的SMTP伺服器地址:smtp.163.com,為了證明你是163的使用者,SMTP伺服器還要求你填寫郵箱地址和郵箱口令,這樣,MUA才能正常地把Email通過SMTP協議傳送到MTA。

類似的,從MDA收郵件時,MDA伺服器也要求驗證你的郵箱口令,確保不會有人冒充你收取你的郵件,所以,Outlook之類的郵件客戶端會要求你填寫POP3或IMAP伺服器地址、郵箱地址和口令,這樣,MUA才能順利地通過POP或IMAP協議從MDA取到郵件。

在使用Python收發郵件前,請先準備好至少兩個電子郵件,如[email protected][email protected][email protected]等,注意兩個郵箱不要用同一家郵件服務商。

 

SMTP傳送郵件的完整程式碼:

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 = '[email protected]';
password = 'cgg5201314'
to_addr = '[email protected]'
smtp_server = 'smtp.163.com'

msg = MIMEText('hello, send by Python...', 'plain', 'utf-8')
msg['From'] = _format_addr('Python愛好者 <%s>' % from_addr)
msg['To'] = _format_addr('管理員 <%s>' % to_addr)
msg['Subject'] = Header('來自SMTP的問候……', 'utf-8').encode()

server = smtplib.SMTP(smtp_server, 25)
server.set_debuglevel(1)
server.login(from_addr, password)
server.sendmail(from_addr, [to_addr], msg.as_string())
server.quit()

控制檯會列印的資訊:

聰哥哥有話說:使用Python的smtplib傳送郵件十分簡單,只要掌握了各種郵件型別的構造方法,正確設定好郵件頭,就可以順利發出。