欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python網(wǎng)絡(luò)編程之使用email、smtplib、poplib、imaplib模塊收發(fā)郵件

 更新時間:2022年05月31日 09:11:36   作者:springsnow  
這篇文章介紹了Python使用email、smtplib、poplib、imaplib模塊收發(fā)郵件的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下

一封電子郵件的旅程是:

  • MUA:Mail User Agent——郵件用戶代理。(即類似Outlook的電子郵件軟件)
  • MTA:Mail Transfer Agent——郵件傳輸代理,就是那些Email服務(wù)提供商,比如網(wǎng)易、新浪等等。
  • MDA:Mail Delivery Agent——郵件投遞代理。Email服務(wù)提供商的某個服務(wù)器

發(fā)件人 -> MUA -> MTA -> MTA -> 若干個MTA -> MDA <- MUA <- 收件人

要編寫程序來發(fā)送和接收郵件,本質(zhì)上就是:

  • 編寫MUA把郵件發(fā)到MTA;
  • 編寫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)點(diǎn)是不但能取郵件,還可以直接操作MDA上存儲的郵件,比如從收件箱移到垃圾箱,等等。

一、SMTP(Simple Mail Transfer Protocol)

即簡單郵件傳輸協(xié)議,它是一組用于由源地址到目的地址傳送郵件的規(guī)則,由它來控制信件的中轉(zhuǎn)方式。

python的smtplib提供了一種很方便的途徑發(fā)送電子郵件。它對smtp協(xié)議進(jìn)行了簡單的封裝。

Python對SMTP支持有smtplibemail兩個模塊,email負(fù)責(zé)構(gòu)造郵件,smtplib負(fù)責(zé)發(fā)送郵件。

1、構(gòu)造郵件:email.mime類型

構(gòu)造一個郵件對象就是一個Messag對象,如果構(gòu)造一個MIMEText對象,就表示一個文本郵件對象,如果構(gòu)造一個MIMEImage對象,就表示一個作為附件的圖片,要把多個對象組合起來,就用MIMEMultipart對象,而MIMEBase可以表示任何對象。它們的繼承關(guān)系如下:

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

首先,我們來構(gòu)造一個最簡單的純文本郵件,然后,通過SMTP發(fā)出去。

from email.mime.text import MIMEText
msg = MIMEText('hello, send by Python...', 'plain', 'utf-8')

注意到構(gòu)造MIMEText對象時,第一個參數(shù)就是郵件正文,第二個參數(shù)是MIME的subtype,傳入'plain',最終的MIME就是'text/plain',最后一定要用utf-8編碼保證多語言兼容性。

2、創(chuàng)建 SMTP 對象

語法如下:

import smtplib
smtpObj = smtplib.SMTP( [host [, port [, local_hostname]]] )

參數(shù)說明:

  • host: SMTP 服務(wù)器主機(jī)。 你可以指定主機(jī)的ip地址或者域名如: runoob.com,這個是可選參數(shù)。
  • port: 如果你提供了 host 參數(shù), 你需要指定 SMTP 服務(wù)使用的端口號,一般情況下 SMTP 端口號為25。
  • local_hostname: 如果 SMTP 在你的本機(jī)上,你只需要指定服務(wù)器地址為 localhost 即可。

3、Python SMTP 對象使用 sendmail 方法發(fā)送郵件

語法如下:

SMTP.sendmail(from_addr, to_addrs, msg[, mail_options, rcpt_options])

參數(shù)說明:

  • from_addr: 郵件發(fā)送者地址。
  • to_addrs: 字符串列表,郵件發(fā)送地址。
  • msg: 發(fā)送消息

這里要注意一下第三個參數(shù),msg 是字符串,表示郵件。我們知道郵件一般由標(biāo)題,發(fā)信人,收件人,郵件內(nèi)容,附件等構(gòu)成,發(fā)送郵件的時候,要注意 msg 的格式。這個格式就是 smtp 協(xié)議中定義的格式。

二、實(shí)例

2:本機(jī)已安裝支持 SMTP 的服務(wù)

以下執(zhí)行實(shí)例需要你本機(jī)已安裝了支持 SMTP 的服務(wù)。

sendmail()方法就是發(fā)郵件,由于可以一次發(fā)給多個人,所以傳入一個list,郵件正文是一個str,as_string()MIMEText對象變成str

經(jīng)過Header對象編碼的文本,包含utf-8編碼信息和Base64編碼的文本。

以下是一個使用 Python 發(fā)送郵件簡單的實(shí)例:

import smtplib
from email.mime.text import MIMEText
from email.header import Header
 
sender = 'from@runoob.com'
receivers = ['429240967@qq.com']  # 接收郵件,可設(shè)置為你的QQ郵箱或者其他郵箱
 
# 三個參數(shù):第一個為文本內(nèi)容,第二個 plain 設(shè)置文本格式,第三個 utf-8 設(shè)置編碼
message = MIMEText('Python 郵件發(fā)送測試內(nèi)容...', 'plain', 'utf-8')
message['From'] = Header("菜鳥教程", 'utf-8')   # 發(fā)送者
message['To'] =  Header("測試", 'utf-8')        # 接收者
message['Subject'] = Header('Python SMTP 郵件測試主題', 'utf-8')
 
try:
    smtpObj = smtplib.SMTP('localhost')
    smtpObj.sendmail(sender, receivers, message.as_string())
    print "郵件發(fā)送成功"
except smtplib.SMTPException:
    print "Error: 無法發(fā)送郵件"

2、使用第三方 SMTP 服務(wù)

如果我們本機(jī)沒有 sendmail 訪問,也可以使用其他郵件服務(wù)商的 SMTP 訪問(QQ、網(wǎng)易、Google等)。

login()方法用來登錄SMTP服務(wù)器

發(fā)收件件人的名字沒有顯示為友好的名字,比如Mr Green 

使用 formataddr方法來格式化一個郵件地址。如果包含中文,需要通過Header對象進(jìn)行編碼。

msg['To']接收的是字符串而不是list,如果有多個郵件地址,用,分隔即可。

import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr

# 第三方 SMTP 服務(wù)
mail_host = "mail.sss.com"  # 設(shè)置服務(wù)器
mail_user = "it_system@sss.com"  # 用戶名
mail_pass = "Ssss201709#"  # 口令

sender = 'it_system@tcl.com'
receivers = 'sss.yang@tcsssl.com'  # 接收郵件,可設(shè)置為你的QQ郵箱或者其他郵箱

message = MIMEText('Python 郵件內(nèi)容測試...', 'plain', 'utf-8')
message['From'] = formataddr(('SCBC-啊iT',   sender))
message['To'] = formataddr(('楊生', receivers))
message['Subject'] = 'Python SMTP 郵件測試'

try:
    smtpObj = smtplib.SMTP()
    smtpObj.connect(mail_host, 25)  # 25 為 SMTP 端口號
    smtpObj.login(mail_user, mail_pass)
    smtpObj.sendmail(sender, receivers, message.as_string())
    print("郵件發(fā)送成功")
except smtplib.SMTPException:
    print("Error: 無法發(fā)送郵件")

3、使用Python發(fā)送HTML格式的郵件

Python在構(gòu)造MIMEText對象時,把HTML字符串傳進(jìn)去,再把第二個參數(shù)由plain變?yōu)?code>html就可以了:

具體代碼如下:

mail_msg = """
Python 郵件內(nèi)容測試...


這是一個鏈接


"""
message = MIMEText(mail_msg, 'html', 'utf-8')

4、Python 發(fā)送帶附件的郵件

帶附件的郵件可以看做包含若干部分的郵件:文本和各個附件本身,所以,可以構(gòu)造一個MIMEMultipart對象代表郵件本身,然后往里面加上一個MIMEText作為郵件正文,再繼續(xù)往里面加上表示附件的MIMEBase對象即可。

發(fā)送帶附件的郵件,首先要創(chuàng)建MIMEMultipart()實(shí)例,然后構(gòu)造附件,如果有多個附件,可依次構(gòu)造,最后利用smtplib.smtp發(fā)送。

from email.mime.multipart import MIMEMultipart

# 創(chuàng)建一個帶附件的實(shí)例
message = MIMEMultipart()

message['From'] = formataddr(('SCBC-啊iT', sender))
message['To'] = formataddr(('楊生', receivers))
message['Subject'] = 'Python SMTP 郵件測試'

mail_msg = """
Python 郵件內(nèi)容測試...


這是一個鏈接


"""
# 郵件正文內(nèi)容
message.attach(MIMEText(mail_msg, 'html', 'utf-8'))

# 構(gòu)造附件1,傳送當(dāng)前目錄下的 test.txt 文件
att = MIMEText(open('32.txt', 'rb').read(), 'base64', 'utf-8')
att["Content-Type"] = 'application/octet-stream'
# 這里的filename可以任意寫,寫什么名字,郵件中顯示什么名字
att["Content-Disposition"] = 'attachment; filename="32.txt"'
message.attach(att)

5、在 HTML 文本中添加圖片

要把圖片嵌入到郵件正文中,我們只需按照發(fā)送附件的方式,先把郵件作為附件添加進(jìn)去,然后,在HTML中通過引用src="cid:0"就可以把附件作為圖片嵌入了。如果有多個圖片,給它們依次編號,然后引用不同的cid:x即可。

郵件的 HTML 文本中一般郵件服務(wù)商添加外鏈?zhǔn)菬o效的,正確添加圖片的實(shí)例如下所示:

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

# 創(chuàng)建一個帶附件的實(shí)例
message = MIMEMultipart()

message['From'] = formataddr(('SCBC-啊iT', sender))
message['To'] = formataddr(('楊生', receivers))
message['Subject'] = 'Python SMTP 郵件測試'

mail_msg = """
Python 郵件內(nèi)容測試...


這是一個鏈接


圖片演示:





"""
# 郵件正文內(nèi)容
message.attach(MIMEText(mail_msg, 'html', 'utf-8'))

# 指定圖片為當(dāng)前目錄
with  open('a.jpg', 'rb') as fp:
    msgImage = MIMEImage(fp.read())

# 定義圖片 ID,在 HTML 文本中引用
msgImage.add_header('Content-ID', '')
message.attach(msgImage)

或者通過MIMEBase來添加圖片

# 指定圖片為當(dāng)前目錄
with  open('a.jpg', 'rb') as fp:
    # 設(shè)置附件的MIME和文件名,這里是png類型:
    mime = MIMEBase('image', 'jpg', filename='a.jpg')
    # 加上必要的頭信息:
    mime.add_header('Content-Disposition', 'attachment', filename='附件顯示名稱.jpg')
    mime.add_header('Content-ID', '')  # 如果有多個文件需要使用.format(index)
    mime.add_header('X-Attachment-Id', '0')  # 如果有多個文件需要使用.format(index)
    # 把附件的內(nèi)容讀進(jìn)來:
    mime.set_payload(fp.read())
    # 用Base64編碼:
    encoders.encode_base64(mime)
    # 添加到MIMEMultipart:
    message.attach(mime)

6、同時支持HTML和Plain格式

如果我們發(fā)送HTML郵件,收件人通過瀏覽器或者Outlook之類的軟件是可以正常瀏覽郵件內(nèi)容的,但是,如果收件人使用的設(shè)備太古老,查看不了HTML郵件怎么辦?

辦法是在發(fā)送HTML的同時再附加一個純文本,如果收件人無法查看HTML格式的郵件,就可以自動降級查看純文本郵件。

利用MIMEMultipart就可以組合一個HTML和Plain,要注意指定subtype是alternative

msg = MIMEMultipart('alternative')
msg['From'] = ...
msg['To'] = ...
msg['Subject'] = ...

msg.attach(MIMEText('hello', 'plain', 'utf-8'))
msg.attach(MIMEText('Hello', 'html', 'utf-8'))
# 正常發(fā)送msg對象...

7、加密SMTP

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

某些郵件服務(wù)商,例如Gmail,提供的SMTP服務(wù)必須要加密傳輸。我們來看看如何通過Gmail提供的安全SMTP發(fā)送郵件。

只需要在創(chuàng)建SMTP對象后,立刻調(diào)用starttls()方法,就創(chuàng)建了安全連接。后面的代碼和前面的發(fā)送郵件代碼完全一樣。

必須知道,Gmail的SMTP端口是587,因此,修改代碼如下:

smtp_server = 'smtp.gmail.com'
smtp_port = 587
server = smtplib.SMTP(smtp_server, smtp_port)
server.starttls()
# 剩下的代碼和前面的一模一樣:
server.set_debuglevel(1)

三、使用poplib接收郵件

收取郵件就是編寫一個MUA作為客戶端,從MDA把郵件獲取到用戶的電腦或者手機(jī)上。收取郵件最常用的協(xié)議是POP協(xié)議,目前版本號是3,俗稱POP3。

Python內(nèi)置一個poplib模塊,實(shí)現(xiàn)了POP3協(xié)議,可以直接用來收郵件。

POP3 的命令和響應(yīng)數(shù)據(jù)都是基于 ASCII 文本的,并以 CR 和 LF(/r/n) 作為行結(jié)束符,響應(yīng)數(shù)據(jù)包括一個表示返回狀態(tài)的符號(+/)和描述信息。

請求和響應(yīng)的標(biāo)準(zhǔn)格式如下:

請求標(biāo)準(zhǔn)格式:命令 [參數(shù)] CRLF
響應(yīng)標(biāo)準(zhǔn)格式:+OK /[-ERR] description CRLF

POP3 協(xié)議客戶端的命令和服務(wù)器端對應(yīng)的響應(yīng)數(shù)據(jù)如下:

  • user name:向 POP 服務(wù)器發(fā)送登錄的用戶名。
  • pass string:向 POP 服務(wù)器發(fā)送登錄的密碼。
  • quit:退出 POP 服務(wù)器。
  • stat:統(tǒng)計郵件服務(wù)器狀態(tài),包括郵件數(shù)和總大小。
  • list [msg_no]:列出全部郵件或指定郵件。返回郵件編號和對應(yīng)大小。
  • retr msg_no:獲取指定郵件的內(nèi)容(根據(jù)郵件編號來獲取,編號從 1 開始)。
  • dele msg_no:刪除指定郵件(根據(jù)郵件編號來刪除,編號從 1 開始)。
  • noop:空操作。僅用于與服務(wù)器保持連接。
  • rset:用于撤銷 dele 命令。

poplib 模塊完全模擬了上面命令,poplib.POP3 或 poplib.POP3_SSL 為上面命令提供了相應(yīng)的方法,開發(fā)者只要依次使用上面命令即可從服務(wù)器端下載對應(yīng)的郵件

注意到POP3協(xié)議收取的不是一個已經(jīng)可以閱讀的郵件本身,而是郵件的原始文本,這和SMTP協(xié)議很像,SMTP發(fā)送的也是經(jīng)過編碼后的一大段文本。

要把POP3收取的文本變成可以閱讀的郵件,還需要用email模塊提供的各種類來解析原始文本,變成可閱讀的郵件對象。

所以,收取郵件分兩步:

第一步:使用poplib.POP3 或 poplib.POP3_SSL 按 POP3 協(xié)議把郵件的原始文本下載到本地;

用POP3獲取郵件其實(shí)很簡單,要獲取所有郵件,只需要循環(huán)使用retr()把每一封郵件內(nèi)容拿到即可。真正麻煩的是把郵件的原始內(nèi)容解析為可以閱讀的郵件對象。

import poplib
from email.parser import Parser
# email.parser 解析電子郵件,返回這個對象的email.message.Message實(shí)例
from email.header import decode_header
from email.utils import parseaddr

# 服務(wù)器及用戶信息
host = 'mail.tcl.com'
username = 'bobin.yang@tcl.com'
password = 'Ybb7654321'

# 連接到POP3服務(wù)器
conn = poplib.POP3_SSL(host)
# 注意qq郵箱使用SSL連接
# 設(shè)置調(diào)試模式,可以看到與服務(wù)器的交互信息
conn.set_debuglevel(1)

# 打印POP3服務(wù)器的歡迎文字
print(conn.getwelcome().decode("utf-8"))

# 身份認(rèn)證
conn.user(username)
conn.pass_(password)

# 獲取服務(wù)器上信件信息,返回一個列表,第一項(xiàng)是一共有多少封郵件,第二項(xiàng)是共有多少字節(jié)
# stat()返回郵件數(shù)量和占用空間
mail_total, total_size = conn.stat()
print('message: %s.Size:%s' % (mail_total, total_size))

# list()返回(response, ['mesg_num octets', ...], octets),第二項(xiàng)是編號
resp, mails, octets = conn.list()
print(mails)
# 返回的列表類似[b'1 82923', b'2 2184', ...]

# 獲取最新一封郵件,注意索引號從1開始
# POP3.retr(which) 檢索序號which的這個郵件,然后設(shè)置他的出現(xiàn)標(biāo)志 返回(response, ['line', ...], octets)這個三元組
resp, lines, ocetes = conn.retr(len(mails))
print('lines:', len(lines))
# lines 存儲了郵件的原始文本的每一行
# 可以獲得整個郵件的原始文本
print("-------------------")

第二步:使用 email.parser.Parser或BytesParser 解析郵件內(nèi)容為消息對象,然后,用適當(dāng)?shù)男问桨燕]件內(nèi)容展示給用戶即可。

解析郵件的過程和上一節(jié)構(gòu)造郵件正好相反。

程序在創(chuàng)建 BytesParser(解析字節(jié)串格式的郵件數(shù)據(jù))或 Parser(解析字符串格式的郵件數(shù)據(jù))時,必須指定 policy=default;否則,BytesParse 或 Parser 解析郵件數(shù)據(jù)得到的就是過時的 Message 對象,,不是新的 EmailMessage,處理起來非常不方便。

1、使用 email.parser.Parser解析郵件內(nèi)容為 email.message.Message(過時,不推薦)

msg = b'\r\n'.join(lines).decode('utf-8')
# 解析出郵件
msg = Parser().parsestr(msg)


# email.Parser.parsestr(text, headersonly=False)
# 與parser()方法類似,不同的是他接受一個字符串對象而不是一個類似文件的對象
# 可選的headersonly表示是否在解析玩標(biāo)題后停止解析,默認(rèn)為否
# 返回根消息對象

# 編碼處理,文本郵件的內(nèi)容也是str,還需要檢測編碼,否則,非UTF-8編碼的郵件都無法正常顯示
def guess_charset(msg):
    charset = msg.get_charset()  # 從msg對象獲取編碼
    if charset is None:
        content_type = msg.get('Content-Type', '').lower()  # 如果獲取不到,再從content—type字段獲取
        if 'charset' in content_type:
            charset = content_type.split('charset=')[1].strip()
            return charset
    return charset


# 數(shù)據(jù)解碼,郵件的Subject或者Email中包含的名字都是經(jīng)過編碼后的str,要正常顯示,就必須decode
def decode_str(s):
    value, charset = decode_header(s)[0]  # 數(shù)據(jù),數(shù)據(jù)編碼方式,from email.header import decode_header
    # decode_header()返回一個list,因?yàn)橄馛c、Bcc這樣的字段可能包含多個郵件地址,所以解析出來的會有多個元素。上面的代碼我們偷了個懶,只取了第一個元素。
    if charset:
        value = value.decode(charset)
    return value


# print_ingo函數(shù):解析郵件與構(gòu)造郵件的步驟正好相反
def print_info(msg, indent=0):  # indent用于縮進(jìn)顯示
    if indent == 0:
        for header in ['From', 'To', 'Subject']:  # 郵件的from、to、subject存在于根對象上
            value = msg.get(header, '')
            if value:
                if header == 'Subject':
                    value = decode_str(value)  # 需要解碼subject字符串
                else:
                    # 解碼mail地址
                    hdr, addr = parseaddr(value)
                    name = decode_str(hdr)
                    value = '%s' % addr
            print('%s:  %s  %s' % (header, value, name))
            print('-*-' * 20)
    if msg.is_multipart():
        # 如果郵件對象是一個is_multipart,get_payload()返回一個list,包含所有子對象
        parts = msg.get_payload()  # 循環(huán)獲得列表項(xiàng)
        for n, part in enumerate(parts):
            # print('%spart %s' % ('  ' * indent, n))
            # print('%s------------' % ('  ' * indent))
            # 遞歸打印沒一個子對象
            print_info(part, indent + 1)
    else:
        # 郵件對象不是一個is_multipart,就根據(jù)content_type判斷
        content_type = msg.get_content_type()  # 數(shù)據(jù)類型
        if content_type == 'text/plain' or content_type == 'text/html':  # 純文本 html文本
            # 純文本或html內(nèi)容
            content = msg.get_payload(decode=True)  # 獲得文本對象的字符串而非對象本身
            charset = guess_charset(msg)  # 要檢測文本編碼
            if charset: content = content.decode(charset)
            content = '%s' % (content)
            print(content)  # 獲取郵件文本內(nèi)容,如果只有文本,打印顯示的結(jié)果和郵件中看的效果一模一樣
        else:
            print(content_type+'不是文本')


print_info(msg, 0)

# 退出
conn.quit()

2、使用email.parser.BytesParser 解析成email.message.EmailMessage對象

如果程序要獲取郵件的發(fā)件人、收件人和主題,直接通過 EmailMessage 的相應(yīng)屬性來獲取即可,與前面為 EmailMessage 設(shè)置發(fā)件人、收件人和主題的方式是對應(yīng)的。
如果程序要讀取 EmailMessage 的各部分,則需要調(diào)用該對象的 walk() 方法,該方法返回一個可迭代對象,程序使用 for 循環(huán)遍歷 walk() 方法的返回值,對郵件內(nèi)容進(jìn)行逐項(xiàng)處理:

  • 如果郵件某項(xiàng)的 maintype 是 'multipart',則說明這一項(xiàng)是容器,用于包含郵件內(nèi)容、附件等其他項(xiàng)。
  • 如果郵件某項(xiàng)的 maintype 是 'text',則說明這一項(xiàng)的內(nèi)容是文本,通常就是郵件正文或文本附件。對于這種文本內(nèi)容,程序直接將其輸出到控制臺中。
  • 如果郵件某項(xiàng)的 maintype 是其他,則說明這一項(xiàng)的內(nèi)容是附件,程序?qū)⒏郊?nèi)容保存在本地文件中。
import os
import poplib
import mimetypes
from email.parser import Parser, BytesParser
from email.policy import default

msg_data = b'\r\n'.join(lines)
# 將字符串內(nèi)容解析成郵件,此處一定要指定policy=default
msg = BytesParser(policy=default).parsebytes(msg_data)
print(type(msg))

print('發(fā)件人:' + msg['from'])
print('收件人:' + msg['to'])
print('主題:' + msg['subject'])
print('第一個收件人名字:' + msg['to'].addresses[0].username)
print('第一個發(fā)件人名字:' + msg['from'].addresses[0].username)
for part in msg.walk():
    counter = 1
    # 如果maintype是multipart,說明是容器(用于包含正文、附件等)
    if part.get_content_maintype() == 'multipart':
        continue
    # 如果maintype是multipart,說明是郵件正文部分
    elif part.get_content_maintype() == 'text':
        print(part.get_content())
    # 處理附件
    else:
        # 獲取附件的文件名
        filename = part.get_filename()
        # 如果沒有文件名,程序要負(fù)責(zé)為附件生成文件名
        if not filename:
            # 根據(jù)附件的contnet_type來推測它的后綴名
            ext = mimetypes.guess_extension(part.get_content_type())
            # 如果推測不出后綴名
            if not ext:
                # 使用.bin作為后綴名
                ext = '.bin'
            # 程序?yàn)楦郊砩晌募?
            filename = 'part-%03d%s' % (counter, ext)
        counter += 1
        # 將附件寫入的本地文件
        with open(os.path.join('.', filename), 'wb') as fp:
            fp.write(part.get_payload(decode=True))
# 退出服務(wù)器,相當(dāng)于發(fā)送POP 3的quit命令
conn.quit()

四、利用imaplib讀取郵件文本內(nèi)容及附件內(nèi)容

通過IMAP協(xié)議來管理郵箱用的,稱作交互郵件訪問協(xié)議。

! encoding:utf8
'''
環(huán)境:
    Win10 64位 Python 2.7.5
參考:
    http://www.pythonclub.org/python-network-application/email-format
    http://blog.sina.com.cn/s/blog_4deeda2501016eyf.html
'''


import imaplib
import email


def parseHeader(message):
    """ 解析郵件首部 """
    subject = message.get('subject')  
    h = email.Header.Header(subject)
    dh = email.Header.decode_header(h)
    subject = unicode(dh[0][0], dh[0][1]).encode('gb2312')
    # 主題
    print subject
    print '
'
    # 發(fā)件人
    print 'From:', email.utils.parseaddr(message.get('from'))[1]
    print '
'
    # 收件人
    print 'To:', email.utils.parseaddr(message.get('to'))[1]
    print '
'
    # 抄送人
    print 'Cc:',email.utils.parseaddr(message.get_all('cc'))[1]



def parseBody(message):
    """ 解析郵件/信體 """
    # 循環(huán)信件中的每一個mime的數(shù)據(jù)塊
    for part in message.walk():
        # 這里要判斷是否是multipart,是的話,里面的數(shù)據(jù)是一個message 列表
        if not part.is_multipart():
            charset = part.get_charset()
            # print 'charset: ', charset
            contenttype = part.get_content_type()
            # print 'content-type', contenttype
            name = part.get_param("name") #如果是附件,這里就會取出附件的文件名
            if name:
                # 有附件
                # 下面的三行代碼只是為了解碼象=?gbk?Q?=CF=E0=C6=AC.rar?=這樣的文件名
                fh = email.Header.Header(name)
                fdh = email.Header.decode_header(fh)
                fname = dh[0][0]
                print '附件名:', fname
                # attach_data = par.get_payload(decode=True) # 解碼出附件數(shù)據(jù),然后存儲到文件中

                # try:
                #     f = open(fname, 'wb') #注意一定要用wb來打開文件,因?yàn)楦郊话愣际嵌M(jìn)制文件
                # except:
                #     print '附件名有非法字符,自動換一個'
                #     f = open('aaaa', 'wb')
                # f.write(attach_data)
                # f.close()
            else:
                #不是附件,是文本內(nèi)容
                print part.get_payload(decode=True) # 解碼出文本內(nèi)容,直接輸出來就可以了。
                # pass
            # print '+'*60 # 用來區(qū)別各個部分的輸出


def getMail(host, username, password, port=993):
    try:
        serv = imaplib.IMAP4_SSL(host, port)
    except Exception, e:
        serv = imaplib.IMAP4(host, port)

    serv.login(username, password)
    serv.select()
    # 搜索郵件內(nèi)容
    typ, data = serv.search(None, '(FROM "xx@xxx.com")')

    count = 1
    pcount = 1
    for num in data[0].split()[::-1]:
        typ, data = serv.fetch(num, '(RFC822)')
        text = data[0][1]
        message = email.message_from_string(text)   # 轉(zhuǎn)換為email.message對象
        parseHeader(message)
        print '
'
        parseBody(message)   
        pcount += 1
        if pcount > count:
            break

    serv.close()
    serv.logout()


if __name__ == '__main__':
    host = "imap.mail_serv.com" # "pop.mail_serv.com"
    username = "Trevor@mail_serv.com"
    password = "your_password"
    getMail(host, username, password)

到此這篇關(guān)于Python收發(fā)郵件的文章就介紹到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評論