用python接收郵件的功能非常的常見(jiàn),我也研究了好久,參考了廖雪峰大大的相關(guān)教程和網(wǎng)上的一些資源才大概了解了相應(yīng)的功能。其中好多代碼是直接參考(copy)別人的旁涤,中文處理方面真的是折磨了我好久外莲。
日常生活中使用QQ郵箱的頻率很高犀斋,我在這里使用的也是QQ郵箱匾南,像以前的話囊骤,QQ郵箱的pop3登錄可以直接使用新密碼就可以直接登錄了猿涨,但現(xiàn)在我發(fā)現(xiàn)直接使用新設(shè)置的密碼會(huì)報(bào)錯(cuò)握童。
poplib.error_proto: b'-ERR Please using authorized code to login.
因此我只能使用短信的方式獲取驗(yàn)證碼。
然后使用之后的授權(quán)碼當(dāng)做密碼就不會(huì)再報(bào)錯(cuò)了叛赚。
首先是登錄郵箱
import poplib
email='392361639@qq.com'
password='授權(quán)碼'
server=poplib.POP3_SSL('pop.qq.com')
server.user(email)
server.pass_(password)
resp, mails, octets = server.list()
index = len(mails)#郵件的總數(shù)
#server.dele(index) 刪除郵件 dele可以用于刪除制定位置的郵件
resp, lines, octets = server.retr(index)#可以取出最新的郵件的信息
msg_content = b'\r\n'.join(lines).decode('utf-8','ignore') #將郵件組合到一起澡绩,生成郵件信息
print(msg_content)
可以看到打印出來(lái)的msg_content文件信息大致是這樣的,里面包含了郵件的頭文件俺附,如Date肥卡,Subject,F(xiàn)rom事镣,TO等信息步鉴。接下來(lái)要取出郵件頭部相關(guān)的信息。上圖的頭部信息并沒(méi)有出現(xiàn)亂碼璃哟,但有的郵件就會(huì)如下圖所示
from email.parser import Parser
from email.header import decode_header
from email.utils import parseaddr#專門處理地址的模塊
#email中專門處理郵件內(nèi)容的模塊
msg = Parser().parsestr(msg_content)
#通過(guò)msg.get('From')等方法可以獲取頭部氛琢,但會(huì)出現(xiàn)編碼不對(duì)
#通過(guò)decode,將Subject其變?yōu)橹形?def decode_str(s):
value, charset = decode_header(s)[0]
if charset:
value = value.decode(charset)
return value
def get_header(msg):
for header in ['From', 'To', 'Subject']:
value = msg.get(header, '')
if value:
#文章的標(biāo)題有專門的處理方法
if header == 'Subject':
value = decode_str(value)
elif header in ['From','To']:
#地址也有專門的處理方法
hdr, addr = parseaddr(value)
value = decode_str(addr)
print(header + ':' + value)
頭部信息取出后接著去正文內(nèi)容随闪,由于我平時(shí)的需求主要為文本信息或者附件阳似,針對(duì)指定郵件獲取信息,或者是取出附件铐伴,對(duì)一些廣告郵件就不需要處理(我也不知道如何去處理)
郵件的正文部分處理
#郵件正文部分
#取附件
#郵件的正文部分在生成器中撮奏,msg.walk()
#如果存在附件,則可以通過(guò).get_filename()的方式獲取文件名稱
def get_file(msg):
for part in msg.walk():
filename=part.get_filename()
if filename!=None:#如果存在附件
filename = decode_str(filename)#獲取的文件是亂碼名稱当宴,通過(guò)之前定義的函數(shù)解碼
data = part.get_payload(decode = True)#取出文件正文內(nèi)容
#此處可以自己定義文件保存位置
path=filename
f = open(path, 'wb')
f.write(data)
f.close()
print(filename,'download')
#接下來(lái)取正文信息
#獲取郵件的字符編碼畜吊,首先在message中尋找編碼,如果沒(méi)有户矢,就在header的Content-Type中尋找
def guess_charset(msg):
charset = msg.get_charset()
if charset is None:
content_type = msg.get('Content-Type', '').lower()
pos = content_type.find('charset=')
if pos >= 0:
charset = content_type[pos+8:].strip()
return charset
def get_content(msg):
for part in msg.walk():
content_type = part.get_content_type()
charset = guess_charset(part)
#如果有附件定拟,則直接跳過(guò)
if part.get_filename()!=None:
continue
email_content_type = ''
content = ''
if content_type == 'text/plain':
email_content_type = 'text'
elif content_type == 'text/html':
print('html 格式 跳過(guò)')
continue #不要html格式的郵件
email_content_type = 'html'
if charset:
try:
content = part.get_payload(decode=True).decode(charset)
#這里遇到了幾種由廣告等不滿足需求的郵件遇到的錯(cuò)誤,直接跳過(guò)了
except AttributeError:
print('type error')
except LookupError:
print("unknown encoding: utf-8")
if email_content_type =='':
continue
#如果內(nèi)容為空逗嫡,也跳過(guò)
print(email_content_type + ' ----- ' + content)
#郵件的正文內(nèi)容就在content中
下面附上完整代碼
import poplib
#解析郵件
from email.parser import Parser
from email.header import decode_header
from email.utils import parseaddr
#解析消息頭中的字符串
#沒(méi)有這個(gè)函數(shù)青自,print出來(lái)的會(huì)使亂碼的頭部信息。如'=?gb18030?B?yrXWpL3hufsueGxz?='這種
#通過(guò)decode驱证,將其變?yōu)橹形?def decode_str(s):
value, charset = decode_header(s)[0]
if charset:
value = value.decode(charset)
return value
#解碼郵件信息分為兩個(gè)步驟延窜,第一個(gè)是取出頭部信息
#首先取頭部信息
#主要取出['From','To','Subject']
'''
From: "=?gb18030?B?anVzdHpjYw==?=" <justonezcc@sina.com>
To: "=?gb18030?B?ztLX1Ly6tcTTys/k?=" <392361639@qq.com>
Subject: =?gb18030?B?dGV4dMTjusM=?=
'''
#如上述樣式,均需要解碼
def get_header(msg):
for header in ['From', 'To', 'Subject']:
value = msg.get(header, '')
if value:
#文章的標(biāo)題有專門的處理方法
if header == 'Subject':
value = decode_str(value)
elif header in ['From','To']:
#地址也有專門的處理方法
hdr, addr = parseaddr(value)
name = decode_str(addr)
#value = name + ' < ' + addr + ' > '
value=name
print(header + ':' + value)
#頭部信息已取出
#獲取郵件的字符編碼抹锄,首先在message中尋找編碼逆瑞,如果沒(méi)有荠藤,就在header的Content-Type中尋找
def guess_charset(msg):
charset = msg.get_charset()
if charset is None:
content_type = msg.get('Content-Type', '').lower()
pos = content_type.find('charset=')
if pos >= 0:
charset = content_type[pos+8:].strip()
return charset
#郵件正文部分
#取附件
#郵件的正文部分在生成器中,msg.walk()
#如果存在附件获高,則可以通過(guò).get_filename()的方式獲取文件名稱
def get_file(msg):
for part in msg.walk():
filename=part.get_filename()
if filename!=None:#如果存在附件
filename = decode_str(filename)#獲取的文件是亂碼名稱哈肖,通過(guò)一開(kāi)始定義的函數(shù)解碼
data = part.get_payload(decode = True)#取出文件正文內(nèi)容
#此處可以自己定義文件保存位置
path=filename
f = open(path, 'wb')
f.write(data)
f.close()
print(filename,'download')
def get_content(msg):
for part in msg.walk():
content_type = part.get_content_type()
charset = guess_charset(part)
#如果有附件,則直接跳過(guò)
if part.get_filename()!=None:
continue
email_content_type = ''
content = ''
if content_type == 'text/plain':
email_content_type = 'text'
elif content_type == 'text/html':
print('html 格式 跳過(guò)')
continue #不要html格式的郵件
email_content_type = 'html'
if charset:
try:
content = part.get_payload(decode=True).decode(charset)
except AttributeError:
print('type error')
except LookupError:
print("unknown encoding: utf-8")
if email_content_type =='':
continue
#如果內(nèi)容為空念秧,也跳過(guò)
print(email_content_type + ' ----- ' + content)
#get_file(msg)
if __name__ == '__main__':
email='392361639@qq.com'
password='ngq*******rznbici'
server=poplib.POP3_SSL('pop.qq.com')
server.user(email)
server.pass_(password)
#登錄的過(guò)程
resp, mails, octets = server.list()
index = len(mails)#郵件的總數(shù)
#此處的循環(huán)是取最近的幾封郵件
for i in range(index-2,index+1):
resp, lines, octets = server.retr(i)#取郵件
msg_content = b'\r\n'.join(lines).decode('utf-8','ignore')
msg = Parser().parsestr(msg_content)
#server.dele(index) 刪除郵件
get_header(msg)
get_file(msg)
get_content(msg)
server.quit()
下面是發(fā)送正文及附件淤井,相對(duì)讀取郵件信息,發(fā)送郵件要比讀取要簡(jiǎn)單很多
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import os
sender = 'justonezcc@sina.com'
receiver = '392361639@qq.com'
subject = 'python email test'
smtpserver = 'smtp.sina.com'
password = '***'
from email import encoders
msgRoot = MIMEMultipart('alternative')
msgRoot['Subject'] = subject
msgRoot['From'] = sender
msgRoot['To']=receiver
#發(fā)送正文
content='你好摊趾,這是一封測(cè)試郵件'
cont=MIMEText(content,'plain','utf-8')
msgRoot.attach(cont)
#發(fā)送附件
file_name='實(shí)證結(jié)果.xls'#要發(fā)送文件的文字
row_path=os.getcwd()#或者其他路徑
path=os.path.join(row_path,file_name)
att = MIMEText(open(path, 'rb').read(), 'base64', 'gb2312')
att["Content-Type"] = 'application/octet-stream'
att.add_header('Content-Disposition', 'attachment', filename=('gb2312', '', file_name))
msgRoot.attach(att)
smtp = smtplib.SMTP()
smtp.connect(smtpserver)
smtp.login(sender, password)
smtp.sendmail(sender, receiver, msgRoot.as_string())
smtp.quit()