Python3收取邮件并合并附件excel

引言

某人需求:从个人邮箱中获取不同人的周小结邮件附件,并合并到一个excel中。
需求分解:

  1. 登陆邮箱,获取邮件列表
  2. 倒序遍历邮件列表,依据时间和关键字筛选符合条件的邮件
  3. 如果邮件有附件,下载附件到指定文件夹
  4. 遍历指定文件夹下excel文件,拷贝其sheet到新建excel中
  5. 保存新excel,完毕。

目前完成基本功能,可适用于一般工作场景,功能简单,容错能力还有待提高。
环境:Python3.6+macOS10.12.3
pip3 install ****安装外部库xlrd和xlwt

代码

#!/usr/bin/python3
# -*- coding: utf-8 -*-
# author: milletluo
# 自动登录邮箱,下载包含关键字和指定日期后的邮件附件
import poplib
import email
import datetime
import time
import os
import xlrd
import xlwt
from email.parser import Parsergg
from email.header import decode_header
from email.utils import parseaddr

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

#邮件的Subject或者Email中包含的名字都是经过编码后的str,要正常显示,就必须decode
def decode_str(s):
    value, charset = decode_header(s)[0]
    if charset:
        value = value.decode(charset)
    return value
#提取文件名,去掉后缀
def GetFileName(filename):
    (filepath,tempfilename) = os.path.split(filename);
    (shotname,extension) = os.path.splitext(tempfilename);
    return shotname
#下载邮件附件
def GetmailAttachment(emailhost,emailuser,emailpass,datestr,keywords):
    host = emailhost
    username = emailuser
    password = emailpass
    keywords = keywords   #查询的邮件的关键字
    datestr = datestr     #查询的邮件日期

    currentpath=os.getcwd()#获取当前目录
    foldername = datestr+keywords#文件夹名和最后输出文件名
    new_path = os.path.join(currentpath, foldername)#文件存储路径
    if os.path.exists(new_path) == False:#如果文件夹不存在,创建文件夹
        os.makedirs(new_path)

    #for 163mail,user POP3 ########
    # pop_conn = poplib.POP3(host)
    #需要验证的邮件服务
    pop_conn = poplib.POP3_SSL(host)
    # 可选:打印POP3服务器的欢迎文字:
    print(pop_conn.getwelcome())
    # 可以打开或关闭调试信息:
    #pop_conn.set_debuglevel(1)
    pop_conn.user(username)
    pop_conn.pass_(password)
    # stat()返回邮件数量和占用空间:
    print('Messages: %s. Size: %s' % pop_conn.stat())
    num = len(pop_conn.list()[1])  #邮件总数
    getfilesucess = 0
    #倒叙遍历邮件
    for i in range(num,0,-1):
        #poplib.rert('邮件号码')方法返回一个元组:(状态信息,邮件,邮件尺寸)
        #hdr,message,octet=server.retr(1) 读去第一个邮件信息.
        #hdr的内容就是响应信息和邮件大小比如'+OK 12498 octets'
        #message 是包含邮件所有行的列表.
        #octet 是这个邮件的内容.
        resp, lines, octets = pop_conn.retr(i)
        # lines存储了邮件的原始文本的每一行,
        # 可以获得整个邮件的原始文本:
        msg_content = b'\r\n'.join(lines).decode('utf-8')
        # 然后解析出邮件:
        msg = Parser().parsestr(msg_content)

        date1 = time.strptime(msg.get("Date")[0:24],'%a, %d %b %Y %H:%M:%S') #格式化收件时间
        date2 = time.strftime("%Y%m%d", date1)
        #如果日期不满足,跳出循环遍历
        if date2<datestr:
            break
        #获取邮件标题和发件人
        for header in ['From', 'Subject']:
            value = msg.get(header, '')
            if value:
                if header=='Subject':
                    subject = decode_str(value)#邮件标题
                    print('邮件标题%s:' % subject)
                else:
                    hdr, addr = parseaddr(value)
                    name = decode_str(hdr)
                    fromname = u'%s' % (name)#发件人名称
                    fromaddr = u'%s' % (addr)#发件人邮箱
        print('发件人%d: %s' % (i,fromname))
        print( "=======================================")
        if keywords in subject:
            for part in msg.walk():
                filename = part.get_filename()
                #不知为何excel附件格式为application/octet-stream
                if filename: #and (contentType == 'application/vnd.ms-excel' or contentType == 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'):
                    data = part.get_payload(decode=True)
                    os.chdir(new_path)
                    fEx = open("%s%s.xlsx"%(date2,fromname), 'wb')
                    fEx.write(data)
                    fEx.close()
                    print('文件下载成功')
                    getfilesucess += 1

                else:
                    print('匹配成功, 但无附件!\n')
                    pass
        else:
            print('无匹配邮件!\n')
    if getfilesucess == 0:
        print('未找到符合条件的邮件')
    else:
        if getfilesucess==1:
            print('仅有1个文件,无须合并!')
        else:
            os.chdir(new_path)
            # 返回一个列表,其中包含在目录条目的名称
            files = os.listdir(new_path)
            outfile = xlwt.Workbook()
            for fname in files:
                sourcefile=GetFileName(fname)
                print(sourcefile)
                print(type(sourcefile))
                data = xlrd.open_workbook(os.path.join(new_path, fname))#打开源表格
                table = data.sheet_by_index(0)#打开源表格sheet
                nrows = table.nrows#源表格数据数目
                newsheet = outfile.add_sheet(sourcefile)#目的表格新增sheet
                #遍历源表格中数据,写入目的表格新增sheet
                for i in range(nrows):
                    for j in range(len(table.row(i))):
                        newsheet.write(i, j,table.row(i)[j].value)
            outname='000'+foldername+'.xls'
            outfile.save(outname)
            print('合并%d个文件到%s!' % (getfilesucess,outname))

    pop_conn.quit()

if __name__ == '__main__':
    #emailhost = raw_input('请输入邮箱服务器地址: ')
    emailhost='pop-mail.outlook.com'
    #emailuser = raw_input('请输入邮箱地址: ')
    emailuser='lm409@hotmail.com'
    emailpass = input('请输入邮箱密码: ')
    #emailpass='***'
    datestr = input('请输入起始日期(如20170401): ')
    keywords = input('请输入关键词: ')
    print('请稍后。。。')
    GetmailAttachment(emailhost,emailuser,emailpass,datestr,keywords)

未解决难点:sheet合并

以上用遍历sheet中每一个单元格的方式拷贝sheet,代码如下:

data = xlrd.open_workbook(os.path.join(new_path, fname))#打开源表格
table = data.sheet_by_index(0)#打开源表格sheet
nrows = table.nrows#源表格数据数目
newsheet = outfile.add_sheet(sourcefile)#目的表格新增sheet
#遍历源表格中数据,写入目的表格新增sheet
for i in range(nrows):
    for j in range(len(table.row(i))):
        newsheet.write(i, j,table.row(i)[j].value)

该方法虽然能完成sheet拷贝,但破坏了表格格式,即拷贝过来的内容是不带格式的分散单元格,例如,若原表格中有合并的单元格,其会被拆散,第一行中读取到值,后面的都为空。不满足原样拷贝sheet的需求。
参考stackoverflow一帖可实现修改固定单元格的数据,而不更改其格式,但是还是不能满足保留格式复制的需求。
据了解,VBA可以比较简便的处理合并多个不同表格的sheet到同一表格这种操作,后续再做尝试。
如果有同学有python的解决方案也感谢留言告知,谢谢!

参考

python读取邮件并下载附件
Python读取邮箱中的邮件,含文本,附件
廖雪峰POP3收取邮件
Python 3 邮件的接收(IMAP)
python合并多个excel表格:openpyxl模块(三)
把多个Excel文件合并到一个Excel文件的多个工作表(Sheet)里

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值