1. 程式人生 > >python介面自動化(三十三)-python自動發郵件總結及例項說明番外篇——下(詳解)

python介面自動化(三十三)-python自動發郵件總結及例項說明番外篇——下(詳解)

簡介

  發郵件前我們需要了解的是郵件是怎麼一個形式去傳送到對方手上的,通俗點來說就是你寫好一封信,然後裝進信封,寫上地址,貼上郵票,然後就近找個郵局,把信仍進去,其他的就不關心了,只是關心時間,而電子郵件不像日常傳送郵件的按天算,時間都是按

秒算的。

電子郵件的傳送流程:

1、你使用某款電子郵件軟體MUA:mail user agent --郵件使用者代理,填寫完成點擊發送

2、在你點擊發送的時候電子郵件軟體發出去,到MTA:mail transfer agent--郵件傳輸代理,即email服務提供商,如網易等

3、MTA--郵箱傳輸代理會把郵箱投遞到郵件的最終目的地MDA:mail delivery agent---郵箱投遞服務

4、email到達MDA後就會放在某個伺服器上,存在資料庫裡,收件人必須通過MUA從MDA中把郵箱放到自己電腦上

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

python發郵件需要掌握兩個模組的用法,smtplib和email,這倆模組是python自帶的,只需import即可使用。smtplib模組主要負責傳送郵件,email模組主要負責構造郵件。

smtplib模組主要負責傳送郵件:是一個傳送郵件的動作,連線郵箱伺服器,登入郵箱,傳送郵件(有發件人,收信人,郵件內容)。

email模組主要負責構造郵件:指的是郵箱頁面顯示的一些構造,如發件人,收件人,主題,正文,附件等。

1.smtplib模組

smtplib使用較為簡單。以下是最基本的語法。

匯入及使用方法如下:

1 import smtplib
2 
3 smtp = smtplib.SMTP() 
4 smtp.connect('smtp.163.com,25') 
5 smtp.login(username, password) 
6 smtp.sendmail(sender, receiver, msg.as_string()) 
7 smtp.quit()

說明:

smtplib.SMTP():例項化SMTP()

connect(host,port):

host:指定連線的郵箱伺服器。常用郵箱的smtp伺服器地址如下:

新浪郵箱:smtp.sina.com,新浪VIP:smtp.vip.sina.com,搜狐郵箱:smtp.sohu.com,126郵箱:smtp.126.com,139郵箱:smtp.139.com,163網易郵箱:smtp.163.com。

port:指定連線伺服器的埠號,預設為25.

login(user,password):

user:登入郵箱的使用者名稱。

password:登入郵箱的密碼,像筆者用的是網易郵箱,網易郵箱一般是網頁版,需要用到客戶端密碼,需要在網頁版的網易郵箱中設定授權碼,該授權碼即為客戶端密碼。

sendmail(from_addr,to_addrs,msg,...):

from_addr:郵件傳送者地址

to_addrs:郵件接收者地址。傳送郵件,多人時用list,字串列表['接收地址1','接收地址2','接收地址3',...]或'接收地址'

msg:傳送訊息:郵件內容。郵件正文是一個str,一般是msg.as_string():as_string()是將msg(MIMEText物件或者MIMEMultipart物件)變為str。

quit(): 退出關閉郵箱,用於結束SMTP會話。

2.email模組

email模組下有mime包,mime英文全稱為“Multipurpose Internet Mail Extensions”,即多用途網際網路郵件擴充套件,是目前網際網路電子郵件普遍遵循的郵件技術規範。

該mime包下常用的有三個模組:text,image,multpart。

匯入方法如下:

from email.mime.multipart import MIMEMultipart    
from email.mime.text import MIMEText    
from email.mime.image import MIMEImage

構造一個郵件物件就是一個Message物件,如果構造一個MIMEText物件,就表示一個文字郵件物件,如果構造一個MIMEImage物件,就表示一個作為附件的圖片,要把多個物件組合起來,就用MIMEMultipart物件,而MIMEBase可以表示任何物件。它們的繼承關係如下:

Message
+- MIMEBase
   +- MIMEMultipart
   +- MIMENonMultipart
      +- MIMEMessage
      +- MIMEText
      +- MIMEImage

2.1 text說明

郵件傳送程式為了防止有些郵件閱讀軟體不能顯示處理HTML格式的資料,通常都會用兩型別分別為"text/plain"和"text/html"

構造MIMEText物件時,第一個引數是郵件正文,第二個引數是MIME的subtype,最後一定要用utf-8編碼保證多語言相容性。

2.1.1新增普通文字

方法很簡單,在構造MIMEText物件時,把TEXT字串傳進去,再把第二個引數plain和第三個引數編碼傳進去即可。plain表示純文字 ,後面的則是編譯,保證多語言相容 

text = "Hi!\nHow are you?\nHere is the link you wanted:\nhttps://www.cnblogs.com/du-hong"    
text_plain = MIMEText(text,'plain', 'utf-8')    

檢視MIMEText屬性:可以觀察到MIMEText,MIMEImage和MIMEMultipart的屬性都一樣。

print dir(text_plain)

['__contains__', '__delitem__', '__doc__', '__getitem__', '__init__', '__len__', '__module__', '__setitem__', '__str__', '_charset', '_default_type', '_get_params_preserve', '_headers', '_payload', '_unixfrom', 'add_header', 'as_string', 'attach', 'defects', 'del_param', 'epilogue', 'get', 'get_all', 'get_boundary', 'get_charset', 'get_charsets', 'get_content_charset', 'get_content_maintype', 'get_content_subtype', 'get_content_type', 'get_default_type', 'get_filename', 'get_param', 'get_params', 'get_payload', 'get_unixfrom', 'has_key', 'is_multipart', 'items', 'keys', 'preamble', 'replace_header', 'set_boundary', 'set_charset', 'set_default_type', 'set_param', 'set_payload', 'set_type', 'set_unixfrom', 'values', 'walk']

2.1.2新增超文字(HTML)

方法也很簡單,在構造MIMEText物件時,把HTML字串傳進去,再把第二個引數由plain變為html就可以了

 1 html = """
 2 <html>  
 3   <body>  
 4     <p> 
 5        Here is the <a href="https://www.cnblogs.com/du-hong">link</a> you wanted.
 6     </p> 
 7   </body>  
 8 </html>  
 9 """    
10 text_html = MIMEText(html,'html', 'utf-8')  

2.1.3新增附件

首先要建立MIMEMultipart()例項,然後構造附件,如果有多個附件,可依次構造,最後利用smtplib.smtp傳送

sendfile=open(r'D:\pythontest\text.txt','rb').read()
text_att = MIMEText(sendfile, 'base64', 'utf-8')    
text_att["Content-Type"] = 'application/octet-stream'    
text_att["Content-Disposition"] = 'attachment; filename="顯示的名字.txt"'  

2.2 image說明

新增圖片:

sendimagefile=open(r'D:\pythontest\testimage.png','rb').read()
image = MIMEImage(sendimagefile)
image.add_header('Content-ID','<image1>')

檢視MIMEImage屬性:

print dir(image)

['__contains__', '__delitem__', '__doc__', '__getitem__', '__init__', '__len__', '__module__', '__setitem__', '__str__', '_charset', '_default_type', '_get_params_preserve', '_headers', '_payload', '_unixfrom', 'add_header', 'as_string', 'attach', 'defects', 'del_param', 'epilogue', 'get', 'get_all', 'get_boundary', 'get_charset', 'get_charsets', 'get_content_charset', 'get_content_maintype', 'get_content_subtype', 'get_content_type', 'get_default_type', 'get_filename', 'get_param', 'get_params', 'get_payload', 'get_unixfrom', 'has_key', 'is_multipart', 'items', 'keys', 'preamble', 'replace_header', 'set_boundary', 'set_charset', 'set_default_type', 'set_param', 'set_payload', 'set_type', 'set_unixfrom', 'values', 'walk']

2.3 multpart說明

常見的multipart型別有三種:multipart/alternative, multipart/related和multipart/mixed。

郵件型別為"multipart/alternative"的郵件包括純文字正文(text/plain)和超文字正文(text/html)。

郵件型別為"multipart/related"的郵件正文中包括圖片,聲音等內嵌資源。

郵件型別為"multipart/mixed"的郵件包含附件。向上相容,如果一個郵件有純文字正文,超文字正文,內嵌資源,附件,則選擇mixed型別。

msg = MIMEMultipart('mixed')

我們必須把Subject,From,To,Date新增到MIMEText物件或者MIMEMultipart物件中,郵件中才會顯示主題,發件人,收件人,時間(若無時間,就預設一般為當前時間,該值一般不設定)。

msg = MIMEMultipart('mixed') 
msg['Subject'] = 'Python email test'
msg['From'] = '[email protected] <[email protected]>'
msg['To'] = '[email protected]'
msg['Date']='2019-5-10'

檢視MIMEMultipart屬性:

msg = MIMEMultipart('mixed') 
print dir(msg) 

結果:

['__contains__', '__delitem__', '__doc__', '__getitem__', '__init__', '__len__', '__module__', '__setitem__', '__str__', '_charset', '_default_type', '_get_params_preserve', '_headers', '_payload', '_unixfrom', 'add_header', 'as_string', 'attach', 'defects', 'del_param', 'epilogue', 'get', 'get_all', 'get_boundary', 'get_charset', 'get_charsets', 'get_content_charset', 'get_content_maintype', 'get_content_subtype', 'get_content_type', 'get_default_type', 'get_filename', 'get_param', 'get_params', 'get_payload', 'get_unixfrom', 'has_key', 'is_multipart', 'items', 'keys', 'preamble', 'replace_header', 'set_boundary', 'set_charset', 'set_default_type', 'set_param', 'set_payload', 'set_type', 'set_unixfrom', 'values', 'walk']

說明:

msg.add_header(_name,_value,**_params):新增郵件頭欄位。

msg.as_string():是將msg(MIMEText物件或者MIMEMultipart物件)變為str,如果只有一個html超文字正文或者plain普通文字正文的話,一般msg的型別可以是MIMEText;如果是多個的話,就都新增到MIMEMultipart,msg型別就變為MIMEMultipart。

msg.attach(MIMEText物件或MIMEImage物件):將MIMEText物件或MIMEImage物件新增到MIMEMultipart物件中。MIMEMultipart物件代表郵件本身,MIMEText物件或MIMEImage物件代表郵件正文。

以上的構造的文字,超文字,附件,圖片都何以新增到MIMEMultipart('mixed')中:

msg.attach(text_plain)    
msg.attach(text_html)    
msg.attach(text_att)    
msg.attach(image)

3.文字,html,圖片,附件實現例項

3.1例項

3.2執行結果

3.3參考程式碼

 1 # coding=utf-8
 2 #1.先設定編碼,utf-8可支援中英文,如上,一般放在第一行
 3 
 4 #2.註釋:包括記錄建立時間,建立人,專案名稱。
 5 '''
 6 Created on 2019-5-10
 7 @author: 北京-巨集哥
 8 Project:學習和使用郵箱發文字,html,圖片,附件實現例項郵件
 9 '''
10 #3.匯入模組
11 import smtplib
12 from email.mime.multipart import MIMEMultipart
13 from email.mime.text import MIMEText
14 from email.mime.image import MIMEImage
15 from email.header import Header
16 
17 # 設定smtplib所需的引數
18 # 下面的發件人,收件人是用於郵件傳輸的。
19 smtpserver = 'smtp.mxhichina.com'
20 username = '[email protected]'
21 password = 'xxxx@@xx3'
22 sender = '[email protected]'
23 # 收件人為一個收件人
24 # receiver='[email protected]'
25 # 收件人為多個收件人
26 receiver = ["[email protected]","[email protected]","[email protected]"]
27 
28 subject = 'Python email test'
29 # 通過Header物件編碼的文字,包含utf-8編碼資訊和Base64編碼資訊。以下中文名測試ok
30 # subject = '中文標題'
31 # subject=Header(subject, 'utf-8').encode()
32 
33 # 構造郵件物件MIMEMultipart物件
34 # 下面的主題,發件人,收件人,日期是顯示在郵件頁面上的。
35 msg = MIMEMultipart('mixed')
36 msg['Subject'] = subject
37 msg['From'] = '北京-巨集哥<[email protected]>'
38 # msg['To'] = "[email protected]","[email protected]","[email protected]"
39 # 收件人為多個收件人,通過join將列表轉換為以;為間隔的字串
40 msg['To'] = ";".join(receiver)
41 # msg['Date']='2019-5-10'
42 
43 # 構造文字內容
44 text = "Hi!\nHow are you?\nHere is the link you wanted:\nhttps://www.cnblogs.com/du-hong"
45 text_plain = MIMEText(text, 'plain', 'utf-8')
46 msg.attach(text_plain)
47 
48 # 構造圖片連結
49 sendimagefile = open(r'E:\pythontest\testimage.png', 'rb').read()
50 image = MIMEImage(sendimagefile)
51 image.add_header('Content-ID', '<image1>')
52 image["Content-Disposition"] = 'attachment; filename="honggeimage.png"'
53 msg.attach(image)
54 
55 # 構造html
56 # 傳送正文中的圖片:由於包含未被許可的資訊,網易郵箱定義為垃圾郵件,報554 DT:SPM :<p><img src="cid:image1"></p>
57 html = """
58 <html>  
59   <head></head>  
60   <body>  
61     <p>Hi!<br>  
62        How are you?<br>  
63        Here is the <a href="https://www.cnblogs.com/du-hong/">link 北京-巨集哥</a> you wanted.<br> 
64     </p> 
65   </body>  
66 </html>  
67 """
68 text_html = MIMEText(html, 'html', 'utf-8')
69 text_html["Content-Disposition"] = 'attachment; filename="texthtml.html"'
70 msg.attach(text_html)
71 
72 # 構造附件
73 sendfile = open(r'E:\pythontest\text.txt', 'rb').read()
74 text_att = MIMEText(sendfile, 'base64', 'utf-8')
75 text_att["Content-Type"] = 'application/octet-stream'
76 # 以下附件可以重新命名成aaa.txt
77 # text_att["Content-Disposition"] = 'attachment; filename="aaa.txt"'
78 # 另一種實現方式
79 text_att.add_header('Content-Disposition', 'attachment', filename='hongge.txt')
80 # 以下中文測試不ok
81 # text_att["Content-Disposition"] = u'attachment; filename="中文附件.txt"'.decode('utf-8')
82 msg.attach(text_att)
83 
84 # 傳送郵件
85 smtp = smtplib.SMTP()
86 smtp.connect('smtp.mxhichina.com')
87 # 我們用set_debuglevel(1)就可以打印出和SMTP伺服器互動的所有資訊。
88 # smtp.set_debuglevel(1)
89 smtp.login(username, password)
90 smtp.sendmail(sender, receiver, msg.as_string())
91 smtp.quit()

說明:

對有些 header 要特別留意,伺服器會針對這些 header 做檢查

User-Agent : 有些伺服器或 Proxy 會通過該值來判斷是否是瀏覽器發出的請求

Content-Type : 在使用 REST 介面時,伺服器會檢查該值,用來確定 HTTP Body 中的內容該怎樣解析。常見的取值有:

application/xml : 在 XML RPC,如 RESTful/SOAP 呼叫時使用

application/json : 在 JSON RPC 呼叫時使用

application/x-www-form-urlencoded : 瀏覽器提交 Web 表單時使用

在使用伺服器提供的 RESTful 或 SOAP 服務時, Content-Type 設定錯誤會導致伺服器拒絕服務

小結

   好了,哈哈,到這裡把python發郵件的十八輩祖宗都被我們挖出來了,自己都感覺到有點缺德,但是我們學習就是需要這種精神,但是也不要過於鑽牛角筋,要適可而止。想必小夥伴們對python發郵件有了更深刻的認識了,以後遇到類似的問題,

往上套就可以了,但是要注意方式和方法,不要生搬硬套,生搬硬套又會出現問題,要靈活有技巧的