• 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

    志同道合一起学习,欢迎加入QQ群:878749917
  • 相关阅读:
    堆和栈的区别
    .net中类(class)与结构(struct)的不同
    CTS、CLS、CLR
    C#和.Net的关系
    装箱(boxing)和拆箱(unboxing)
    三层架构
    属性和public字段的区别(调用set方法为一个属性设值,然后用get方法读取出来的值一定是set进去的值吗?)
    override与重载(overload)的区别
    C#中的委托是什么?事件是不是一种委托?事件和委托的关系。
    json转树状菜单栏
  • 原文地址:https://www.cnblogs.com/gujianjian/p/12762040.html
Copyright © 2020-2023  润新知