【实用教程】批量解析EML邮件文件,AI辅助快速生成年终总结
在年底撰写工作总结时,邮件记录是最真实的工作轨迹凭证。手动整理数十上百封邮件不仅耗时,还容易遗漏关键信息。本文将分享一个Python脚本,可批量解析EML格式邮件,自动汇总发件人、收件人、主题、正文等核心信息,生成结构化的文本报告,直接投喂AI即可快速生成高质量年终总结。
一、教程核心价值
- 解放双手:批量处理任意数量EML文件,无需手动打开每封邮件
- 结构化汇总:自动提取邮件关键信息,按统一格式整理
- AI友好:生成的纯文本报告可直接作为AI提示词,快速生成年终总结
- 编码兼容:完美解决中文邮件、中文路径乱码问题
二、环境准备
1. 安装Python
确保本地安装Python 3.7及以上版本(推荐3.9+),可从Python官网下载安装。
2. 安装依赖库
打开命令提示符(CMD)或终端,执行以下命令安装所需依赖:
bash
pip install html2text pywin32
html2text:将邮件中的HTML格式正文转为纯文本pywin32:解决Windows系统中文路径访问问题
三、完整代码实现
将以下代码保存为eml_summary.py文件:
python
import email
import quopri
import base64
import html2text
from email.header import decode_header
import os
import glob
from datetime import datetime
import sys
# 解决中文路径问题
if sys.platform == 'win32':
import win32api
import win32con
def decode_email_header(header_value):
"""解码邮件头(处理中文等非ASCII字符)"""
if not header_value:
return ""
decoded_parts = decode_header(header_value)
header_parts = []
for part, encoding in decoded_parts:
if isinstance(part, bytes):
if encoding:
header_parts.append(part.decode(encoding, errors='replace'))
else:
# 尝试常见编码
try:
header_parts.append(part.decode('utf-8'))
except:
try:
header_parts.append(part.decode('gbk'))
except:
header_parts.append(part.decode('latin-1'))
else:
header_parts.append(part)
return ''.join(header_parts)
def decode_base64_content(content, charset='utf-8'):
"""专门解码base64编码的邮件正文"""
try:
# 先解码base64
decoded_bytes = base64.b64decode(content)
# 再解码字符集
return decoded_bytes.decode(charset, errors='replace')
except Exception as e:
try:
return decoded_bytes.decode('gbk', errors='replace')
except:
return decoded_bytes.decode('latin-1', errors='replace')
def decode_email_body(part):
"""解码邮件正文内容(增强版)"""
# 获取原始payload
payload = part.get_payload(decode=False)
charset = part.get_content_charset() or 'utf-8'
# 处理不同的传输编码
transfer_encoding = part.get('Content-Transfer-Encoding', '').lower()
if transfer_encoding == 'base64':
# 专门处理base64编码
text = decode_base64_content(payload, charset)
elif transfer_encoding == 'quoted-printable':
# 处理quoted-printable编码
decoded_bytes = quopri.decodestring(payload)
try:
text = decoded_bytes.decode(charset, errors='replace')
except:
text = decoded_bytes.decode('gbk', errors='replace')
else:
# 普通编码
try:
text = payload.decode(charset, errors='replace')
except:
try:
text = payload.decode('gbk', errors='replace')
except:
text = payload.decode('latin-1', errors='replace')
return text
def extract_email_content(eml_file_path):
"""解析单个EML文件(修复中文路径和编码问题)"""
try:
# 处理Windows中文路径问题
if sys.platform == 'win32':
eml_file_path = win32api.GetShortPathName(eml_file_path)
# 读取EML文件(使用rb模式避免编码问题)
with open(eml_file_path, 'rb') as f:
msg = email.message_from_bytes(f.read())
# 提取邮件基本信息
email_info = {
'文件名': os.path.basename(eml_file_path),
'发件人': decode_email_header(msg.get('From', '')),
'收件人': decode_email_header(msg.get('To', '')),
'抄送': decode_email_header(msg.get('Cc', '')),
'主题': decode_email_header(msg.get('Subject', '')),
'邮件日期': decode_email_header(msg.get('Date', '')),
'正文': '',
'解析状态': '成功'
}
# 提取正文内容
body_text = ""
body_html = ""
# 遍历邮件部分
if msg.is_multipart():
for part in msg.walk():
content_type = part.get_content_type()
content_disposition = str(part.get("Content-Disposition"))
# 跳过附件
if "attachment" in content_disposition:
continue
# 提取纯文本内容
if content_type == "text/plain":
body_text = decode_email_body(part)
# 提取HTML内容(后续转为文本)
elif content_type == "text/html":
body_html = decode_email_body(part)
else:
# 非多部分邮件
content_type = msg.get_content_type()
if content_type == "text/plain":
body_text = decode_email_body(msg)
elif content_type == "text/html":
body_html = decode_email_body(msg)
# 优先使用纯文本,若无则将HTML转为文本
if body_text:
email_info['正文'] = body_text
elif body_html:
# 将HTML转为纯文本(优化配置)
h2t = html2text.HTML2Text()
h2t.ignore_links = False
h2t.ignore_images = True
h2t.unicode_snob = True
h2t.body_width = 0
email_info['正文'] = h2t.handle(body_html)
except Exception as e:
# 详细记录错误信息
error_msg = f'失败:{str(e)}'
email_info = {
'文件名': os.path.basename(eml_file_path),
'解析状态': error_msg,
'发件人': '',
'收件人': '',
'抄送': '',
'主题': '',
'邮件日期': '',
'正文': ''
}
print(f"解析 {os.path.basename(eml_file_path)} 出错:{error_msg}")
return email_info
def save_summary_to_txt(email_info_list, output_file_path):
"""将所有解析后的邮件内容汇总保存为TXT文件"""
# 确保输出目录存在
output_dir = os.path.dirname(output_file_path)
if output_dir and not os.path.exists(output_dir):
os.makedirs(output_dir)
with open(output_file_path, 'w', encoding='utf-8', errors='replace') as f:
# 写入汇总标题
f.write("=" * 80 + "\n")
f.write(f"EML文件批量解析汇总报告\n")
f.write(f"汇总时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
f.write(f"解析文件总数:{len(email_info_list)}\n")
f.write(f"成功解析数:{len([x for x in email_info_list if x['解析状态'] == '成功'])}\n")
f.write(f"失败解析数:{len([x for x in email_info_list if x['解析状态'] != '成功'])}\n")
f.write("=" * 80 + "\n\n")
# 遍历每个邮件的解析结果
for idx, email_info in enumerate(email_info_list, 1):
f.write(f"【第{idx}个文件】\n")
f.write("-" * 60 + "\n")
# 写入该邮件的所有信息
for key, value in email_info.items():
if value: # 只写入非空内容
if key == '正文':
f.write(f"{key}:\n{value}\n\n")
else:
f.write(f"{key}:{value}\n")
# 每个文件之间的分隔符
f.write("\n" + "=" * 80 + "\n\n")
def main():
# 配置输出文件路径
output_txt = "EML文件汇总解析结果.txt"
# 获取当前文件夹下所有.eml文件(处理中文路径)
current_dir = os.getcwd()
eml_files = []
for file in os.listdir(current_dir):
if file.lower().endswith('.eml'):
eml_files.append(os.path.join(current_dir, file))
# 检查是否找到EML文件
if not eml_files:
print("错误:当前文件夹下未找到任何.eml文件")
return
print(f"找到 {len(eml_files)} 个.eml文件,开始批量解析...")
print("-" * 50)
# 批量解析每个EML文件
email_info_list = []
for eml_file in eml_files:
print(f"正在解析:{os.path.basename(eml_file)}")
email_content = extract_email_content(eml_file)
email_info_list.append(email_content)
# 打印解析状态
status = "✅ 成功" if email_content['解析状态'] == '成功' else "❌ 失败"
print(f"状态:{status}")
# 保存汇总结果
print("\n正在保存汇总结果...")
save_summary_to_txt(email_info_list, output_txt)
# 输出汇总信息
print("-" * 50)
print(f"批量解析完成!")
print(f"汇总结果已保存至:{os.path.abspath(output_txt)}")
print(f"📊 汇总统计:")
print(f" 总文件数:{len(eml_files)}")
success_count = len([x for x in email_info_list if x['解析状态'] == '成功'])
fail_count = len([x for x in email_info_list if x['解析状态'] != '成功'])
print(f" 成功解析:{success_count}")
print(f" 失败解析:{fail_count}")
# 输出失败的文件列表(如果有)
failed_files = [x['文件名'] for x in email_info_list if x['解析状态'] != '成功']
if failed_files:
print(f"\n❌ 解析失败的文件:")
for file in failed_files[:10]: # 只显示前10个
print(f" - {file}")
if len(failed_files) > 10:
print(f" - ... 还有 {len(failed_files)-10} 个文件解析失败")
if __name__ == "__main__":
# 设置系统编码
if sys.platform == 'win32':
os.system('chcp 65001 > nul') # 设置控制台编码为UTF-8
# 安装依赖(首次运行时取消注释执行)
# os.system("pip install html2text pywin32")
main()
四、使用步骤
1. 整理EML文件
将需要解析的所有EML格式邮件文件,复制到eml_summary.py脚本所在的文件夹中。
2. 运行脚本
- Windows系统 :双击
eml_summary.py文件,或在脚本所在文件夹按住Shift+右键,选择"在此处打开命令窗口",执行python eml_summary.py - Mac/Linux系统 :打开终端,切换到脚本所在目录,执行
python3 eml_summary.py
3. 查看解析结果
脚本运行完成后,会在同一目录生成EML文件汇总解析结果.txt文件,包含:
- 汇总统计(总文件数、成功/失败数)
- 每封邮件的完整信息(文件名、发件人、收件人、主题、日期、正文)
- 错误提示(解析失败的文件及原因)
五、核心功能解析
1. 编码处理
decode_email_header:解码邮件头中的中文内容,自动适配UTF-8、GBK等编码decode_email_body:处理Base64、Quoted-Printable等编码格式的邮件正文- 解决Windows中文路径访问问题,避免文件读取失败
2. 内容提取
- 自动区分纯文本/HTML格式正文,HTML正文自动转为纯文本
- 跳过邮件附件,只提取核心文本内容
- 完整提取发件人、收件人、抄送、主题、日期等关键信息
3. 结果汇总
- 生成结构化的TXT报告,便于阅读和AI处理
- 详细的解析状态统计,方便排查问题
六、AI生成年终总结技巧
将生成的EML文件汇总解析结果.txt内容复制,作为提示词投喂给AI(如ChatGPT、文心一言、讯飞星火等),示例提示词:
请基于以下邮件记录,帮我生成一份2024年度工作总结,要求:
1. 总结工作成果和完成的项目
2. 分析工作中的亮点和不足
3. 提出2025年的工作计划和改进方向
4. 语言正式、逻辑清晰,分点阐述,字数约1500字
【邮件记录开始】
[粘贴TXT文件中的所有内容]
【邮件记录结束】
AI提示词优化建议:
- 指定角色:"以XX岗位的身份"、"站在团队负责人的角度"
- 明确结构:"分为工作成果、问题反思、未来规划三部分"
- 突出重点:"重点体现项目推进、客户沟通、跨部门协作的工作内容"
- 调整风格:"语言简洁干练"、"突出数据和成果"
七、常见问题解决
1. 脚本运行提示缺少模块
执行pip install 缺失的模块名,如pip install html2text
2. 中文乱码
- 确保脚本文件编码为UTF-8
- Windows系统已自动设置控制台编码为UTF-8(脚本内置处理)
- 生成的TXT文件用Notepad++等编辑器打开,选择UTF-8编码
3. 部分邮件解析失败
- 检查EML文件是否损坏
- 特殊格式的邮件(如加密、特殊编码)可能解析失败,可手动打开查看
- 查看控制台的错误提示,针对性处理
八、扩展优化建议
- 按时间筛选:增加邮件日期筛选功能,只解析指定时间段的邮件
- 关键词提取:集成jieba分词,自动提取邮件中的核心关键词
- Excel导出:将结果导出为Excel格式,便于数据筛选和分析
- 分类汇总:按发件人/主题/项目自动分类邮件内容
- 批量导出附件:增加附件提取功能,汇总邮件中的附件文件
总结
本教程提供的EML邮件批量解析脚本,能快速将分散的邮件记录转化为结构化的文本报告,结合AI工具可大幅提升年终总结的撰写效率。不仅适用于年终总结,还可用于项目复盘、工作汇报、客户沟通记录整理等场景,是职场高效办公的实用工具。
通过简单的脚本调整,还能适配更多个性化需求,建议根据自己的工作场景优化使用,让数据整理和总结撰写更高效!