python 郵件模塊

????Python內(nèi)置對(duì)SMTP的支持,其中細(xì)化為smtplibemail兩個(gè)模塊,email負(fù)責(zé)構(gòu)造郵件,smtplib負(fù)責(zé)發(fā)送郵件,我們僅僅需要編輯相關(guān)配置即可

1. 獲取認(rèn)證

????在獲取認(rèn)證這一塊我們需要編輯的配置就是我們的郵箱賬戶(hù)以及授權(quán)碼了,兩者都可以在電子郵箱的賬戶(hù)配置中找到,這里以QQ郵箱做案例

image.png

2. STMP屬性

????smtplib模塊負(fù)責(zé)郵件的發(fā)送,可以通過(guò)from smtplib import SMTP導(dǎo)入模塊并通過(guò)help(SMTP)查看相應(yīng)用法,我們通過(guò)server = smtplib.SMTP(smtp_server, port)構(gòu)建一個(gè)server對(duì)象,然后參照以下方法執(zhí)行相關(guān)配置

方法 描述
SMTP.set_debuglevel(level) 設(shè)置輸出debug調(diào)試信息,默認(rèn)不輸出
SMTP.docmd(cmd[, argstring]) 發(fā)送一個(gè)命令到SMTP服務(wù)器
SMTP.connect([host[, port]]) 連接到指定的SMTP服務(wù)器
SMTP.helo([hostname]) 使用helo指令向SMTP服務(wù)器確認(rèn)你的身份
SMTP.ehlo(hostname) 使用ehlo指令像ESMTP(SMTP擴(kuò)展)確認(rèn)你的身份
SMTP.ehlo_or_helo_if_needed() 如果在以前的會(huì)話連接中沒(méi)有提供ehlo或者h(yuǎn)elo指令,這個(gè)方法會(huì)調(diào)用ehlo()或helo()
SMTP.has_extn(name) 判斷指定名稱(chēng)是否在SMTP服務(wù)器上
SMTP.verify(address) 判斷郵件地址是否在SMTP服務(wù)器上
SMTP.starttls([keyfile[, certfile]]) 使SMTP連接運(yùn)行在TLS模式,所有的SMTP指令都會(huì)被加密
SMTP.login(user, password) 登錄SMTP服務(wù)器
SMTP.sendmail(from_addr, to_addrs, msg, mail_options=[], rcpt_options=[]) 發(fā)送郵件 (from_addr:郵件發(fā)件人) (to_addrs:郵件收件人) (msg:發(fā)送消息)
SMTP.quit() 關(guān)閉SMTP會(huì)話
SMTP.close() 關(guān)閉SMTP服務(wù)器連接

3. 發(fā)送郵件

????簡(jiǎn)單的郵件可以通過(guò)MIMEText構(gòu)建信息然后調(diào)用sendmail方法即可,但是這樣的簡(jiǎn)單處理不會(huì)顯示發(fā)送人、收件人、主題等等。

from email.mime.text import MIMEText
msg = MIMEText('your message', 'plain', 'utf-8')
  • 這里可以通過(guò)改變信息類(lèi)型的值選擇傳輸不同的文本,比如這里的plain改成html就可以在信息中通過(guò)HTML格式輸出,MIME相關(guān)內(nèi)容可以參考MIME 類(lèi)型

????郵件主題、發(fā)件人、收件人等信息包含于MTA文本中的我們只需要簡(jiǎn)單配置幾行代碼

def _format_addr(s):
    name, addr = parseaddr(s)
    return formataddr((Header(name, 'utf-8').encode(), addr))

msg = MIMEText('your message', 'plain', 'utf-8')
msg['From'] = _format_addr('Maya <%s>' % from_addr)
msg['To'] = _format_addr('Receiver <%s>' % to_addr)
msg['Subject'] = Header('Your Subject……', 'utf-8').encode()
  • 很多郵件中會(huì)將用戶(hù)和郵箱做如下顯示:user <XXX@XX.com>,email.utils.parseaddr則是用來(lái)專(zhuān)門(mén)解析郵件地址的,把它解析為一個(gè)列表,第一項(xiàng)是用戶(hù)名, 第二項(xiàng)是郵箱地址
  • 郵件中包含中文的話,需要通過(guò)Header對(duì)象進(jìn)行編碼
  • msg['To']接收的是字符串而不是list,如果有多個(gè)郵件地址,用,分隔

4. 附件添加

????帶附件的郵件可以看做包含若干部分的郵件:文本和各個(gè)附件本身,所以,可以構(gòu)造一個(gè)MIMEMultipart對(duì)象代表郵件本身,然后往里面加上一個(gè)MIMEText作為郵件正文,再繼續(xù)往里面加上表示附件的MIMEBase對(duì)象即可,簡(jiǎn)單來(lái)說(shuō)就是首先用MIMEMultipart來(lái)標(biāo)明郵件由多個(gè)部分構(gòu)成,通過(guò)add_header等方法進(jìn)行附件的聲明

MIMEBase
    |-- MIMENonMultipart
        |-- MIMEApplication
        |-- MIMEAudio
        |-- MIMEImage
        |-- MIMEMessage
        |-- MIMEText
    |-- MIMEMultipart

????一般來(lái)說(shuō),不會(huì)用到MIMEBase,而是直接使用它的繼承類(lèi)。MIMEMultipartattach方法,而MIMENonMultipart沒(méi)有,只能被attach。
MIME上述等支持的類(lèi)型,如果附件是圖片格式,我要用MIMEImage,如果是音頻,要用MIMEAudio,可以根據(jù)類(lèi)型判定,也可以直接使用MIMEApplicationMIMEApplication默認(rèn)子類(lèi)型是application/octet-stream(二進(jìn)制文件)


class email.mime.base.MIMEBase(_maintype,_subtype,** _ params )


????這是所有MIME特定子類(lèi)的基類(lèi) Message。通常你不會(huì)特別創(chuàng)建實(shí)例MIMEBase,盡管你可以。 MIMEBase 主要是為更具體的MIME感知子類(lèi)提供方便的基類(lèi)。

  • *_maintype**Content-Type*主要類(lèi)型(例如文本圖像),_ subtype*Content-Type*次要類(lèi)型(例如*plain**gif*)。 *_params*是一個(gè)參數(shù)鍵/值字典,直接傳遞給Message.add_header。

  • MIMEBase班總是增加了一個(gè)內(nèi)容類(lèi)型頭(基于*_maintype*,*_subtype**_params*)和 *MIME-版本*頭(始終設(shè)置為1.0)。

  • 可以通過(guò)mimetypes.guess_type(url,strict = True )判斷具體類(lèi)型,無(wú)法判斷就統(tǒng)一設(shè)置成二進(jìn)制文件

        ctype, encoding = mimetypes.guess_type(filePath)
        if ctype is None or encoding is not None:
            ctype = 'application/octet-stream'
        maintype, subtype = ctype.split('/', 1)

5. 具體操作

# 郵件對(duì)象:
msg = MIMEMultipart()
msg['From'] = _format_addr('Your message <%s>' % from_addr)
msg['To'] = _format_addr('Your name <%s>' % to_addr)
msg['Subject'] = Header('Your Subject……', 'utf-8').encode()

# 郵件正文是MIMEText:
msg.attach(MIMEText('send with file...', 'plain', 'utf-8'))

# 添加附件就是加上一個(gè)MIMEBase,從本地讀取一個(gè)圖片:
with openfilePath, 'rb') as f:
    # 設(shè)置附件的MIME和文件名,這里是png類(lèi)型:
    mime = MIMEBase(maintype, subtype, filename)
    # 加上必要的頭信息:
    mime.add_header('Content-Disposition', 'attachment', filename)
    mime.add_header('Content-ID', '<0>')
    mime.add_header('X-Attachment-Id', '0')
    # 把附件的內(nèi)容讀進(jìn)來(lái):
    mime.set_payload(f.read())
    # 用Base64編碼:
    encoders.encode_base64(mime)
    # 添加到MIMEMultipart:
    msg.attach(mime)

6. 加密傳輸

????使用標(biāo)準(zhǔn)的25端口連接SMTP服務(wù)器時(shí),使用的是明文傳輸,發(fā)送郵件的整個(gè)過(guò)程可能會(huì)被竊聽(tīng)。要更安全地發(fā)送郵件,可以加密SMTP會(huì)話,實(shí)際上就是先創(chuàng)建SSL安全連接,然后再使用SMTP協(xié)議發(fā)送郵件,QQ郵箱也是支持SSL加密的

QQ郵箱
接收郵件服務(wù)器:pop.qq.com,使用SSL,端口號(hào)995
發(fā)送郵件服務(wù)器:smtp.qq.com,使用SSL,端口號(hào)465或587
image.png
smtp_server = 'smtp.qq.com'
smtp_port = 587
server = smtplib.SMTP(smtp_server, smtp_port)
server.starttls()
# 剩下的代碼和前面的一模一樣:
server.set_debuglevel(1)
...

7. 總結(jié)

  • STMP同樣支持圖片的傳輸以及在正文中顯示,用處并不廣泛不做概述
  • 可以設(shè)定一個(gè)布爾值利用try catch接收郵件發(fā)送的返回碼做后續(xù)處理
  • From、To 要與 sendmail中的前兩個(gè)參數(shù)保持一致
  • To 多個(gè)郵箱用逗號(hào)隔開(kāi),sendmail 中的第二個(gè)參數(shù)要用 list
  • subject 中不能含有 test 關(guān)鍵字,否則會(huì)被視為垃圾郵件

Reference

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容