imap指定郵箱搜索特殊郵件下載——合理利用search
作者:故箋箋
鏈接地址:https://www.cnblogs.com/gujianjian/p/12762040.html
說明:碼農不易,請尊重他人勞動成果共創和諧網絡環境。本文轉載請備注原作出處,違者必究。
背景:上一篇我們描述了怎么下載指定郵箱的所有郵件的附件和正文,沒有附件就下載正文,主要是考慮到如果發件人並沒有按照附件的格式下載,然后發文本放在了正文里面燈因素,也主要是為了統計交了多少個作業,未交的有多少,以方便提醒對方提交......而這次的需求是,每天會有固定的人發送固定的郵件給我,我需要每天下載,並進行數據處理,發送給各個老板。簡單而言就是下載郵箱(imap)->數據處理(pandas)->文件發送微信(請查看我歷史博客有講解怎么發送文件到微信)定期轟炸老板!!!!!
一、登錄郵箱,我是封裝成一個小def,方便調用。
def Start_mailbox(host,post,uesr,passwrod):#啟動imap郵箱服務(作者:故箋箋) try: conn = imaplib.IMAP4(host, post) conn.login(uesr, passwrod) print("Connect to {0}:{1} successfully".format(host, post)) return conn except BaseException as e: print("Connect to {0}:{1} failed".format(host, post), e)
主函數主要是設置各種參數,和調用def,其他的沒了。
# ******************主程序(作者:故箋箋)************************# #參數設置 pattern_uid = re.compile('\d+ \(UID (?P<uid>\d+)\)') #設置獲取UID的正則表達式,通過UID去進行文件的copy和delect Download_path = r'E:\郵箱下載' #設置郵箱下載路徑 old_maildir = 'INBOX' #收件箱 new_maildir = '&XfJfUmhj-/&Ytt1H4v0Zg5PGmVwY24-' #移動的目標郵箱 rubbish_maildir = '&XfJfUmhj-/&U4ZT8leDVz5lh072-' #垃圾箱 host = 'imap.263.net' post = '143' uesr = '***********.com' passwrod = '*******' #啟動imap郵箱服務 conn = Start_mailbox(host,post,uesr,passwrod) imap4(conn,old_maildir,new_maildir,Download_path) ''' #查看imap郵箱有多少個文件夾,imap郵箱名字不是ut-f8編碼,不能自動編譯,需自行查看 try: type_, folders = conn.list() for i in folders: print(i.decode(type_)) except BaseException as e: print("the {0}:{1} no file".format("imap.263.net", 143), e) '''
二、imap4(conn,old_maildir,new_maildir,Download_path) def 的使用
這里我們講一下search的用法,第一個參數是指編碼方式,第二個方式類似於篩選,ALL表示整個文件夾下的所有文件,或者指定某種規律的方式來進行篩選郵件,具體的參數設定可以參考相應的文獻內容。此處我們就得到了收件箱里面發送人是"**aaaa**.com"的所有郵件了,然后把找到的郵件列表傳遞給list。
conn.select(old_maildir, readonly=True) #打開指定的郵箱文件下,我的old_maildir指定的是收件箱,一般收到的文件也都會在此處。 type_, data = conn.search('GB2312','FROM "**aaaa**.com"') #重點中的重點 mail_list = data[0].split()#傳輸當前文件夾下的文件給mail_list
接下來,我們根據每個郵箱的id,就可以來操作了。當然,這里我只是操作了下載文件,類似於正文,音頻,圖片等請參考其他博客文章。
mail_list = data[0].split()#傳輸當前文件夾下的文件給mail_list,作者:故箋箋 print('{}個文件被找到!'.format(len(mail_list))) for num in mail_list: type_, data = conn.fetch(num,'(RFC822)') msg = email.message_from_string(data[0][1].decode('utf-8'))#傳輸郵件全部內容,用email解析 From_mail = email.utils.parseaddr(msg.get('from'))[1] From_mail_name = From_mail.split('@')[0] mail_title,mail_charset = email.header.decode_header(msg.get('Subject'))[0] mail_title = mail_title.decode(mail_charset) print(mail_title) for part in msg.walk(): if not part.is_multipart(): filename = part.get_filename() #如果是附件,這里就會取出附件的文件名 if filename: print('下載文件') fname,file_charset = email.header.decode_header(filename)[0] fname = fname.decode(file_charset) attach_data = part.get_payload(decode=True) savefile(fname, attach_data, Download_path) else: print('不是附件') pass #下載一個文件之后把這個文件移動到新的郵件文件夾,以便后面遍歷for少一些數據。內容在下面。print ('</br>') pcount += 1
由於我收到的文件都是中文,這里就會涉及到郵件標題的解碼和附件,一般解碼我們用到的是email的email.header.decode_header,這樣解碼下來的是一個list,第一個參數是字符,第二個參數是編碼方式,然后我們再把字符按照它給的編碼方式進行編碼,就可以得到我們的中文。
fname,file_charset = email.header.decode_header(filename)[0]
fname = fname.decode(file_charset)
得到附件的中文名稱,我們還要獲取附件,並且保存,保存用open的方法,也可以參考with會更好,,當然對於這種小功能,最好封裝成def,便於代碼的閱讀和維護。
def savefile(filename, data, path):#保存文件方法(保存在path目錄下) try: filepath = path +r'\\'+ filename print(filepath) fn = open(filepath, 'wb') except: print('filename error') fn.close() fn.write(data) fn.close()
得到附件,並調用保存的def:
attach_data = part.get_payload(decode=True)
savefile(fname, attach_data, Download_path)
其實想一想,如果我們就這樣完了,每一次,我們都會去查找收件箱里面的發送人是"**aaaa**.com"的所有郵件然后下載,第二次我們是不是會重復下載之前的數據,如果長期下來,你郵箱已經有1000份郵件了,那就要下載1000次,這樣的代碼執行起來是非常不perfect的,所以,基於imap的郵箱操作,我實現的方法是每一次操作,都把郵件移動到新的文件夾,並刪除收件箱里的文件,這樣就可以保證,每次我從收件箱收到的都是發送人最新發送的郵件。
#下載一個文件之后把這個文件移動到新的郵件文件夾,以便后面遍歷for少一些數據。作者:故箋箋 try: resp,data = conn.fetch(num,'(UID)') match = pattern_uid.match(data[0].decode('utf-8')) msg_uid = match.group('uid') remove_email_file(old_maildir,new_maildir,msg_uid) except BaseException as e: print("remove email failed", e)
每個郵箱都有自己的uid,我們用pattern_uid = re.compile('\d+ \(UID (?P<uid>\d+)\)')這樣的正則,去取出fetch里的uid,通過UID去進行COPY和delect,當然,按照我的臭習慣,我把復制和刪除封裝成了一個小def。
def remove_email_file(old_maildir,new_maildir,msg_uid):#移動郵箱文件夾 ,作者:故箋 try: conn.select(old_maildir, readonly=False) type_, data = conn.search(None,"ALL") result = conn.uid('COPY',msg_uid,new_maildir) print('copy successful:') if result[0]=='OK': conn.select(old_maildir, readonly=False) type_,data = conn.search(None,"ALL") mov,data = conn.uid('STORE',msg_uid, '+FLAGS', '(\\Deleted)') conn.expunge() print('delect successful:') except BaseException as e: print('fail error:',e)
這樣就完成了每次下載指定發送人發來的郵件,並且每次都只執行一個for,只下載一次,大大優化了代碼。
以下是全部的代碼實現,分享給大家,不用每次都要去郵箱操作了,或許,你可以再深思一步,如何對收件箱里面的郵件進行分類,整理?
import imaplib import email from email.parser import Parser import re,os def Start_mailbox(host,post,uesr,passwrod):#啟動imap郵箱服務 try: conn = imaplib.IMAP4(host, post) conn.login(uesr, passwrod) print("[+] Connect to {0}:{1} successfully".format(host, post)) return conn except BaseException as e: print("Connect to {0}:{1} failed".format(host, post), e) def savefile(filename, data, path):#保存文件方法(保存在path目錄下) try: filepath = path +r'\\'+ filename print(filepath) fn = open(filepath, 'wb') except: print('filename error') fn.close() fn.write(data) fn.close() def remove_email_file(old_maildir,new_maildir,msg_uid):#移動郵箱文件夾 try: conn.select(old_maildir, readonly=False) type_, data = conn.search(None,"ALL") result = conn.uid('COPY',msg_uid,new_maildir) print('copy successful:') if result[0]=='OK': conn.select(old_maildir, readonly=False) type_,data = conn.search(None,"ALL") mov,data = conn.uid('STORE',msg_uid, '+FLAGS', '(\\Deleted)') conn.expunge() print('delect successful:') except BaseException as e: print('fail error:',e) def imap4(conn,old_maildir,new_maildir,Download_path): conn.select(old_maildir, readonly=True) type_, data = conn.search('GB2312','FROM "cuiyongle-fesco@sunlands.com"')#'(SUBJECT "招生說明會到課數據"'.encode('gb2312')指定標題 pcount = 1 mail_list = data[0].split()#傳輸當前文件夾下的文件給mail_list print('{}個文件被找到!'.format(len(mail_list))) for num in mail_list: type_, data = conn.fetch(num,'(RFC822)') msg = email.message_from_string(data[0][1].decode('utf-8'))#傳輸郵件全部內容,用email解析 From_mail = email.utils.parseaddr(msg.get('from'))[1] From_mail_name = From_mail.split('@')[0] mail_title,mail_charset = email.header.decode_header(msg.get('Subject'))[0] mail_title = mail_title.decode(mail_charset) print(mail_title) for part in msg.walk(): if not part.is_multipart(): filename = part.get_filename() #如果是附件,這里就會取出附件的文件名 if filename: print('下載文件') fname,file_charset = email.header.decode_header(filename)[0] fname = fname.decode(file_charset) attach_data = part.get_payload(decode=True) savefile(fname, attach_data, Download_path) else: print('不是附件') pass #下載一個文件之后把這個文件移動到新的郵件文件夾,以便后面遍歷for少一些數據。 try: resp,data = conn.fetch(num,'(UID)') match = pattern_uid.match(data[0].decode('utf-8')) msg_uid = match.group('uid') remove_email_file(old_maildir,new_maildir,msg_uid) except BaseException as e: print("remove email failed", e) print ('</br>') pcount += 1 conn.close() conn.logout() # ******************主程序,作者,故箋,轉載請備注出處,尊重別人勞動成果************************# #參數設置 pattern_uid = re.compile('\d+ \(UID (?P<uid>\d+)\)') Download_path = r'E:\郵箱下載' old_maildir = 'INBOX' new_maildir = '&XfJfUmhj-/&Ytt1H4v0Zg5PGmVwY24-' rubbish_maildir = '&XfJfUmhj-/&U4ZT8leDVz5lh072-' host = 'imap.263.net' post = '143' uesr = '*********.com' passwrod = '*********' #啟動imap郵箱服務 conn = Start_mailbox(host,post,uesr,passwrod) imap4(conn,old_maildir,new_maildir,Download_path) ''' #查看imap郵箱有多少個文件夾,imap郵箱名字不是ut-f8編碼,不能自動編譯,需自行查看 try: type_, folders = conn.list() for i in folders: print(i.decode(type_)) except BaseException as e: print("the {0}:{1} no file".format("imap.263.net", 143), e) '''
在學習python的路上,懵懵懂懂,每天要查上百分博客,文獻。走千萬個坑.....其實我想認識想一起在python路上成長的小伙伴,一起努力學習成長,如果有意願,志同道合一起學習,歡迎加入QQ群:878749917