Python 实战:15 行代码批量提取邮件附件报销单,自动生成汇总表(附完整代码)
光是下载附件就花了半小时,还因为漏看了 3 封邮件,导致同事的报销延迟提交,被追着问了好几天。打开生成的 “9 月报销汇总表.xlsx”,会看到两个工作表:“报销明细”(所有报销项目的详细数据)和 “员工总报销”(每人总金额),格式工整,直接打印或发审批群都没问题。每月报销季,同事会通过企业邮箱发送报销邮件,每封邮件含 1 个 Excel 附件(命名格式:“张三_9 月报销.xlsx”“李四_9
上周财务报销季,我被 20 多封报销邮件搞到崩溃 —— 每个同事发的邮件里都带一个 Excel 报销单,需要手动下载附件、打开核对 “报销项目、金额、发票号”,再复制到总表。光是下载附件就花了半小时,还因为漏看了 3 封邮件,导致同事的报销延迟提交,被追着问了好几天。
后来想起 Python 能操作邮件和 Excel,花了 1 小时写了段代码,没想到自动下载所有附件、提取关键信息、生成汇总表一步到位,全程只用了 2 分钟。现在把这个实战案例分享出来,不管是财务还是行政,只要会复制代码,就能告别手动处理邮件附件的麻烦。
一、先明确问题:我们要解决什么报销处理痛点?
每月报销季,同事会通过企业邮箱发送报销邮件,每封邮件含 1 个 Excel 附件(命名格式:“张三_9 月报销.xlsx”“李四_9 月报销.xlsx”),附件里有 “报销项目、金额、发票号、报销日期”4 列数据,需要完成 3 件事:
- 批量下载附件:自动识别报销邮件,下载所有 Excel 附件到指定文件夹;
- 提取关键信息:从每个附件中提取 “姓名、报销项目、金额、发票号”(姓名从附件名获取);
- 生成汇总表:把所有数据汇总到一个 Excel,方便核对和审批。
手动处理时,不仅要逐封邮件下载附件,还要担心漏看或录错数据;用 Python 的话,依赖imaplib(操作邮件)、pandas(处理 Excel)两个库,就能全程自动化。
二、准备工作:5 分钟搭好环境
首先安装所需 Python 库,打开 “命令提示符”(Windows)或 “终端”(Mac),输入以下命令:
pip install pandas openpyxl imaplib2
- pandas+openpyxl:用于读取 Excel 附件、生成汇总表;
- imaplib2:支持连接企业邮箱,读取邮件和附件(比自带imaplib更稳定)。
然后提前准备 3 个关键信息(后续代码要用到):
- 企业邮箱地址(如 “finance@company.com”);
- 邮箱授权码(不是登录密码!在邮箱设置里开启 “IMAP 服务” 后获取,不同邮箱获取方式不同,比如网易邮箱在 “账户安全” 里申请);
- 邮件主题关键词(如 “9 月报销”,确保能精准识别报销邮件,避免下载其他附件)。
三、代码实现:分 3 步搞定报销附件处理
第一步:连接邮箱,批量下载报销附件
先通过 IMAP 协议连接企业邮箱,筛选出含 “9 月报销” 关键词的邮件,自动下载附件到指定文件夹。
代码带详细注释,新手也能看懂:
# 导入需要的库
import imaplib
import email
from email.header import decode_header
import os
import pandas as pd
# 1. 连接邮箱,下载报销附件
# 邮箱配置信息(替换成你的实际信息)
email_user = "finance@company.com" # 你的邮箱地址
email_password = "abc123def456" # 邮箱授权码(不是登录密码)
imap_server = "imap.163.com" # 邮箱IMAP服务器(网易是imap.163.com,腾讯是imap.qq.com)
attachment_save_path = "D:\\9月报销附件" # 附件保存路径
subject_keyword = "9月报销" # 报销邮件主题关键词
# 创建附件保存文件夹(如果不存在)
if not os.path.exists(attachment_save_path):
os.makedirs(attachment_save_path)
# 连接IMAP服务器
mail = imaplib.IMAP4_SSL(imap_server)
mail.login(email_user, email_password)
mail.select("inbox") # 选择收件箱
# 搜索含关键词的邮件(UTF-8编码,避免中文乱码)
keyword = f'"*{subject_keyword}*"'
status, data = mail.search(None, 'SUBJECT', keyword.encode('utf-8'))
email_ids = data[0].split() # 获取所有符合条件的邮件ID
# 遍历邮件,下载附件
for email_id in email_ids:
status, msg_data = mail.fetch(email_id, "(RFC822)")
msg = email.message_from_bytes(msg_data[0][1])
# 解码邮件主题(避免中文乱码)
subject = decode_header(msg["Subject"])[0][0]
if isinstance(subject, bytes):
subject = subject.decode("utf-8")
# 遍历邮件附件
for part in msg.walk():
# 判断是否为附件
if part.get_content_disposition() == "attachment":
# 解码附件名称
filename = decode_header(part.get_filename())[0][0]
if isinstance(filename, bytes):
filename = filename.decode("utf-8")
# 只保存Excel附件(避免下载其他格式文件)
if filename.endswith(".xlsx"):
# 保存附件到指定路径
attachment_path = os.path.join(attachment_save_path, filename)
with open(attachment_path, "wb") as f:
f.write(part.get_payload(decode=True))
print(f"已下载附件:{filename}")
# 关闭邮箱连接
mail.logout()
print(f"\n所有报销附件已保存到:{attachment_save_path}")
运行这段代码后,打开 “D:\9 月报销附件” 文件夹,会看到所有同事的 Excel 报销单已自动下载,不用再逐封邮件点击 “下载附件”。
第二步:提取附件关键信息,合并成总数据
接着读取所有下载的 Excel 附件,提取 “姓名(从文件名获取)、报销项目、金额、发票号”,合并成一个总 DataFrame。
代码继续往下写:
# 2. 提取附件信息,合并数据
all_reimbursement = [] # 存放所有报销数据
# 遍历附件文件夹里的Excel文件
for filename in os.listdir(attachment_save_path):
if filename.endswith(".xlsx"):
# 从文件名提取员工姓名(如“张三_9月报销.xlsx”提取“张三”)
employee_name = filename.split("_")[0]
# 读取Excel附件(假设数据在第一个工作表,列名是“报销项目、金额、发票号、报销日期”)
file_path = os.path.join(attachment_save_path, filename)
df = pd.read_excel(file_path, engine="openpyxl")
# 添加“员工姓名”列,方便后续汇总
df["员工姓名"] = employee_name
# 只保留需要的列(避免无关数据干扰)
df = df[["员工姓名", "报销项目", "金额", "发票号"]]
# 处理可能的空值(金额为空的行跳过)
df = df.dropna(subset=["金额"])
# 确保金额是数值类型(避免后续汇总出错)
df["金额"] = pd.to_numeric(df["金额"], errors="coerce").fillna(0)
all_reimbursement.append(df)
# 合并所有报销数据
total_reimbursement = pd.concat(all_reimbursement, ignore_index=True)
# 按员工姓名分组,计算每人总报销金额(可选,用于快速核对)
employee_total = total_reimbursement.groupby("员工姓名")["金额"].sum().reset_index()
employee_total.columns = ["员工姓名", "总报销金额"]
print("\n各员工总报销金额:")
print(employee_total)
print(f"\n所有报销数据共{len(total_reimbursement)}行")
运行后,控制台会显示每个员工的总报销金额,比如 “张三 总报销金额 1280 元”,还能看到总数据行数,方便快速核对是否有遗漏。
第三步:生成带格式的报销汇总表
最后把合并后的数据保存成 Excel 汇总表,加个简单格式(表头加粗、调整列宽),方便财务审批。
代码如下:
# 3. 生成报销汇总Excel表
summary_save_path = os.path.join(attachment_save_path, "9月报销汇总表.xlsx")
# 使用ExcelWriter添加格式
with pd.ExcelWriter(summary_save_path, engine="openpyxl") as writer:
# 写入“所有报销明细”工作表
total_reimbursement.to_excel(writer, sheet_name="报销明细", index=False)
# 写入“员工总报销”工作表
employee_total.to_excel(writer, sheet_name="员工总报销", index=False)
# 给“报销明细”表加格式
worksheet1 = writer.sheets["报销明细"]
# 调整列宽
worksheet1.column_dimensions["A"].width = 12 # 员工姓名
worksheet1.column_dimensions["B"].width = 20 # 报销项目
worksheet1.column_dimensions["C"].width = 10 # 金额
worksheet1.column_dimensions["D"].width = 15 # 发票号
# 表头加粗
from openpyxl.styles import Font
header_font = Font(bold=True)
for col in range(1, 5):
worksheet1.cell(row=1, column=col).font = header_font
# 给“员工总报销”表加格式
worksheet2 = writer.sheets["员工总报销"]
worksheet2.column_dimensions["A"].width = 12
worksheet2.column_dimensions["B"].width = 15
for col in range(1, 3):
worksheet2.cell(row=1, column=col).font = header_font
print(f"\n报销汇总表已保存到:{summary_save_path}")
打开生成的 “9 月报销汇总表.xlsx”,会看到两个工作表:“报销明细”(所有报销项目的详细数据)和 “员工总报销”(每人总金额),格式工整,直接打印或发审批群都没问题。我上次生成后,财务同事说 “比手动汇总的表清楚多了,还不用核对数据”。
更多推荐
所有评论(0)