python接收163郵件以及下載附件(以163郵箱為例)
阿新 • • 發佈:2020-12-16
python利用pop3接收郵件以及下載附件(以163郵箱為例)
1、首先需要引入相關的模組,主要就是兩個模組:pop3(接收郵件)和email(解析郵件內容)
# POP3(Post Office Protocol 3),即郵局協議的第3個版本, #是電子郵件的第一個離線協議標準。該協議把郵件下載到本地計算機, #不與伺服器同步,缺點是更易丟失郵件或多次下載相同的郵件。 import poplib # 引入用來解析郵件相關資訊的模組 from email.parser import Parser from email.header import decode_header from email.utils import parseaddr #引入相關時間庫 from datetime import datetime #引入專門處理時間和日期的模組,arrow是一個輕量級Python庫 import arrow
2、再定義一些與郵件相關的全域性變數
# 輸入自己163的郵箱地址。 user_email_address = '[email protected]' # 郵箱的授權碼,注意:不是登入密碼 user_password = 'SMSRDEQCIUKYODOR' # 這個是163郵箱的pop3的伺服器地址,各個公司的郵箱平臺的POP3的伺服器地址都是不同的,自己網上查詢下即可 #例如:qq郵箱的pop3伺服器地址是:pop.qq.com pop_server_host = 'pop.163.com' # 郵箱對應的pop伺服器的監聽埠 #(如果設定POP3的SSL加密方式連線的話,則埠為:995),否則就是埠為110 pop_server_port = 995
3、定義郵箱連線校驗的函式
def connect_email_by_pop3(): try: # 連線pop伺服器。如果沒有使用SSL,將POP3_SSL()改成POP3(),且監聽埠改為:110即可 email_server = poplib.POP3_SSL(host=pop_server_host, port=pop_server_port, timeout=10) print("連線pop伺服器-------正常,開始驗證使用者郵箱") except: print("連線pop伺服器-------異常,退出") exit(1) try: # 驗證使用者郵箱 email_server.user(user_email_address) print("使用者郵箱驗證-------正常,開始驗證郵箱授權碼") except: print("使用者郵箱驗證-------異常,退出") exit(1) try: # 驗證郵箱密碼是否正確,注意不是登入密碼,是授權碼 email_server.pass_(user_password) print("郵箱授權碼驗證-------正常,開始接受郵箱以及附件") except: print("郵箱授權碼驗證-------異常,退出") exit(1) #開始處理郵箱相關資訊 parse_email_server(email_server)
注意:如果出現連線pop伺服器問題,可能是自己的郵箱沒有設定開啟POP3服務,如qq郵箱的。
4、定義處理郵箱相關資訊的函式
def parse_email_server(email_server):
resp, mails, octets = email_server.list()
num, total_size = email_server.stat()
print("郵件數量為:" + str(num))
# mails儲存了郵件編號列表,
index = len(mails)
# 倒序遍歷郵件
for i in range(index, 0, -1):
# 倒序遍歷郵件,這樣取到的第一封就是最新郵件
resp, lines, octets = email_server.retr(i)
# lines儲存了郵件的原始文字的每一行,
# 郵件的原始文字:# lines是郵件內容,列表形式使用join拼成一個byte變數
msg_content = b'\r\n'.join(lines).decode('utf-8')
# 解析郵件:
msg = Parser().parsestr(msg_content)
# 郵件時間,解析時間格式
mail_datetime = parse_mail_time(msg.get("date"))
max_mail_time_str = arrow.get(mail_datetime).format("YYYY-MM-DD HH:mm")
# 這個可以作為根據時間進行郵件的過濾解析,這個把時間寫死判斷,比較侷限,可以在第一個接收時,把最新的郵件接收時間寫入到自定義的檔案中,
# 等第二次接收郵件時,再取檔案中的時間,進行判斷,用於過濾
# if (max_mail_time_str > "2020-01-01 00:00:00"):
# continue
print("郵件接收時間為:" + max_mail_time_str)
# 解析郵件具體內容,包括正文,標題,和附件
parser_content(msg, 0)
# 別忘記退出
email_server.quit()
5、定義解析郵件具體內容
def parser_content(msg, indent):
if indent == 0:
# 郵件的From, To, Subject存在於根物件上:
#呼叫解析郵件頭部內容的函式
parser_email_header(msg)
# 下載附件
for part in msg.walk():
file_name = part.get_filename() # 獲取附件名稱型別
if file_name is None:
continue
# 說明不是文字,則作為附件處理
filename = decode_str(file_name) # 對附件名稱進行解碼
data = part.get_payload(decode=True) # 下載附件
att_file = open('E:/emailFiles/' + filename, 'wb') # 在指定目錄下建立檔案,注意二進位制檔案需要用wb模式開啟
att_file.write(data) # 儲存附件
att_file.close()
print("附件:" + filename + "儲存成功!")
if (msg.is_multipart()):
# 如果郵件物件是一個MIMEMultipart,
# get_payload()返回list,包含所有的子物件:
parts = msg.get_payload()
for n, part in enumerate(parts):
# 遞迴列印每一個子物件:
return parser_content(part, indent + 1)
else:
# 解析正文
content_type = msg.get_content_type()
if content_type == 'text/plain' or content_type == 'text/html':
# 純文字或HTML內容:
content = msg.get_payload(decode=True)
# 要檢測文字編碼:
charset = guess_charset(msg)
if charset:
content = content.decode(charset)
print('%s正文內容為: %s' % (' ' * indent, content))
6、定義解析頭部內容的相關函式
# 解析郵件
def parser_email_header(msg):
# 解析郵件標題
subject = msg['Subject']
value, charset = decode_header(subject)[0]
if charset:
value = value.decode(charset)
print('郵件標題: {0}'.format(value))
# 解析傳送人資訊
hdr, addr = parseaddr(msg['From'])
# name 傳送人郵箱名稱, addr 傳送人郵箱地址
name, charset = decode_header(hdr)[0]
if charset:
name = name.decode(charset)
print('傳送人郵箱名稱: {0},傳送人郵箱地址: {1}'.format(name, addr))
# 解析接收人資訊
hdr, addr = parseaddr(msg['To'])
# name 傳送人郵箱名稱, addr 傳送人郵箱地址
name, charset = decode_header(hdr)[0]
if charset:
name = name.decode(charset)
print('接收人郵箱名稱: {0},接收人郵箱地址: {1}'.format(name, addr))
7、其它相關定義函式
# 解碼
def decode_str(s):
value, charset = decode_header(s)[0]
if charset:
value = value.decode(charset)
return value
# 猜測字元編碼
def guess_charset(msg):
# 先從msg物件獲取編碼:
charset = msg.get_charset()
if charset is None:
# 如果獲取不到,再從Content-Type欄位獲取:
content_type = msg.get('Content-Type', '').lower()
for item in content_type.split(';'):
item = item.strip()
if item.startswith('charset'):
charset = item.split('=')[1]
break
return charset
#郵件時間處理函式
def parse_mail_time(mail_datetime):
GMT_FORMAT = "%a, %d %b %Y %H:%M:%S"
GMT_FORMAT2 = "%d %b %Y %H:%M:%S"
index = mail_datetime.find(' +0')
if index > 0:
mail_datetime = mail_datetime[:index] # 去掉+0800
formats = [GMT_FORMAT, GMT_FORMAT2]
for ft in formats:
try:
mail_datetime = datetime.strptime(mail_datetime, ft)
return mail_datetime
except:
pass
raise Exception("郵件時間格式解析錯誤")
8、入口
# 比較規範寫法,象徵著程式入口
if __name__ == "__main__":
connect_email_by_pop3()