Python
內置對SMTP
的支持,其中細化爲smtplib
和smtplib
負責發送郵件,我們僅僅需要編輯相關配置即可
1. 獲取認證
在獲取認證這一塊我們需要編輯的配置就是我們的郵箱賬戶以及授權碼了,兩者都可以在電子郵箱的賬戶配置中找到,這裏以
QQ郵箱
做案例
2. STMP屬性
smtplib
模塊負責郵件的發送,可以通過from smtplib import SMTP
導入模塊並通過help(SMTP)
查看相應用法,我們通過server = smtplib.SMTP(smtp_server, port)
構建一個server
對象,然後參照以下方法執行相關配置
方法 | 描述 |
---|---|
SMTP.set_debuglevel(level) | 設置輸出debug調試信息,默認不輸出 |
SMTP.docmd(cmd[, argstring]) | 發送一個命令到SMTP服務器 |
SMTP.connect([host[, port]]) | 連接到指定的SMTP服務器 |
SMTP.helo([hostname]) | 使用helo指令向SMTP服務器確認你的身份 |
SMTP.ehlo(hostname) | 使用ehlo指令像ESMTP(SMTP擴展)確認你的身份 |
SMTP.ehlo_or_helo_if_needed() | 如果在以前的會話連接中沒有提供ehlo或者helo指令,這個方法會調用ehlo()或helo() |
SMTP.has_extn(name) | 判斷指定名稱是否在SMTP服務器上 |
SMTP.verify(address) | 判斷郵件地址是否在SMTP服務器上 |
SMTP.starttls([keyfile[, certfile]]) | 使SMTP連接運行在TLS模式,所有的SMTP指令都會被加密 |
SMTP.login(user, password) | 登錄SMTP服務器 |
SMTP.sendmail(from_addr, to_addrs, msg, mail_options=[], rcpt_options=[]) | 發送郵件 (from_addr:郵件發件人) (to_addrs:郵件收件人) (msg:發送消息) |
SMTP.quit() | 關閉SMTP會話 |
SMTP.close() | 關閉SMTP服務器連接 |
3. 發送郵件
簡單的郵件可以通過
MIMEText
構建信息然後調用sendmail
方法即可,但是這樣的簡單處理不會顯示發送人、收件人、主題等等。
from email.mime.text import MIMEText
msg = MIMEText('your message', 'plain', 'utf-8')
- 這裏可以通過改變信息類型的值選擇傳輸不同的文本,比如這裏的
plain
改成html
就可以在信息中通過HTML
格式輸出,MIME
相關內容可以參考MIME 類型
郵件主題、發件人、收件人等信息包含於
MTA
文本中的我們只需要簡單配置幾行代碼
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()
- 很多郵件中會將用戶和郵箱做如下顯示:
user <[email protected]>
,email.utils.parseaddr則是用來專門解析郵件地址的,把它解析爲一個列表,第一項是用戶名, 第二項是郵箱地址 - 郵件中包含中文的話,需要通過Header對象進行編碼
-
msg['To']
接收的是字符串而不是list,如果有多個郵件地址,用,
分隔
4. 附件添加
帶附件的郵件可以看做包含若干部分的郵件:
文本和各個附件本身
,所以,可以構造一個MIMEMultipart
對象代表郵件本身,然後往裏面加上一個MIMEText
作爲郵件正文,再繼續往裏面加上表示附件的MIMEBase
對象即可,簡單來說就是首先用MIMEMultipart
來標明郵件由多個部分構成,通過add_header
等方法進行附件的聲明
MIMEBase
|-- MIMENonMultipart
|-- MIMEApplication
|-- MIMEAudio
|-- MIMEImage
|-- MIMEMessage
|-- MIMEText
|-- MIMEMultipart
一般來說,不會用到
MIMEBase
,而是直接使用它的繼承類。MIMEMultipart
有attach
方法,而MIMENonMultipart
沒有,只能被attach
。
MIME
上述等支持的類型,如果附件是圖片格式,我要用MIMEImage
,如果是音頻,要用MIMEAudio
,可以根據類型判定,也可以直接使用MIMEApplication
,MIMEApplication
默認子類型是application/octet-stream(二進制文件)
class email.mime.base.MIMEBase(_maintype,_subtype,** _ params )
這是所有
MIME
特定子類的基類Message
。通常你不會特別創建實例MIMEBase
,儘管你可以。MIMEBase
主要是爲更具體的MIME感知子類提供方便的基類。
*_maintype*
是*Content-Type*
主要類型(例如文本 或圖像),_ subtype是*Content-Type*
次要類型(例如*plain*
或*gif*
)。*_params*
是一個參數鍵/值字典,直接傳遞給Message.add_header
。該
MIMEBase
班總是增加了一個內容類型頭(基於*_maintype*
,*_subtype*
和*_params*
)和*MIME-版本*
頭(始終設置爲1.0
)。可以通過
mimetypes.guess_type(url,strict = True )
判斷具體類型,無法判斷就統一設置成二進制文件
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. 具體操作
# 郵件對象:
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'))
# 添加附件就是加上一個MIMEBase,從本地讀取一個圖片:
with openfilePath, 'rb') as f:
# 設置附件的MIME和文件名,這裏是png類型:
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')
# 把附件的內容讀進來:
mime.set_payload(f.read())
# 用Base64編碼:
encoders.encode_base64(mime)
# 添加到MIMEMultipart:
msg.attach(mime)
6. 加密傳輸
使用標準的25端口連接
SMTP
服務器時,使用的是明文傳輸,發送郵件的整個過程可能會被竊聽。要更安全地發送郵件,可以加密SMTP
會話,實際上就是先創建SSL
安全連接,然後再使用SMTP
協議發送郵件,QQ郵箱
也是支持SSL
加密的
QQ郵箱
接收郵件服務器:pop.qq.com,使用SSL,端口號995
發送郵件服務器:smtp.qq.com,使用SSL,端口號465或587
smtp_server = 'smtp.qq.com'
smtp_port = 587
server = smtplib.SMTP(smtp_server, smtp_port)
server.starttls()
# 剩下的代碼和前面的一模一樣:
server.set_debuglevel(1)
...
7. 總結
-
STMP
同樣支持圖片的傳輸以及在正文中顯示,用處並不廣泛不做概述 - 可以設定一個布爾值利用
try catch
接收郵件發送的返回碼做後續處理 -
From、To
要與sendmail
中的前兩個參數保持一致 -
To
多個郵箱用逗號隔開,sendmail
中的第二個參數要用list
-
subject
中不能含有test
關鍵字,否則會被視爲垃圾郵件