python——imap指定郵箱搜索特殊郵件下載


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM