如何在文件名中识别两位标识符并自动发送对应PDF文件至指定邮箱?
解决带前缀后缀的PDF文件名中提取标识符并匹配邮箱发送的问题
我懂你现在的痛点——原来的脚本只能处理像A1.pdf这种纯标识符命名的PDF,但实际工作里的文件名都是带前缀后缀的,比如XYZ_A1_123.pdf、XYZ_QQ_456.pdf这类,得先把中间那两位唯一标识符准确揪出来,再匹配CSV里的邮箱发送,对吧?下面我给你一套完整的Python解决方案,一步步帮你搞定:
1. 准备工作
首先确保你安装了必要的工具:
- 如果用
pandas处理CSV(更简洁),执行pip install pandas安装; - 发邮件用的
smtplib和email是Python标准库,不需要额外安装。
2. 核心步骤拆解
2.1 读取CSV的ID-邮箱映射
先把CSV里的ID和邮箱存成字典,这样查找起来效率最高。这里给你两种实现方式:
方式1:用pandas(推荐,代码更简洁)
import pandas as pd csv_path = "你的邮箱映射文件.csv" # 假设CSV列名是"ID"和"Email",读取后转成字典 email_map = pd.read_csv(csv_path).set_index("ID")["Email"].to_dict()
方式2:用Python标准库csv(无需额外安装)
import csv email_map = {} with open(csv_path, mode='r', encoding='utf-8') as file: reader = csv.DictReader(file) # 先检查CSV是否包含必要列 if "ID" not in reader.fieldnames or "Email" not in reader.fieldnames: raise ValueError("CSV必须包含'ID'和'Email'两列") for row in reader: # 去除前后空格,避免匹配失败 identifier = row["ID"].strip() email = row["Email"].strip() if identifier and email: email_map[identifier] = email
2.2 提取PDF文件名中的两位标识符
关键是用正则表达式精准匹配文件名里的两位标识符。根据你给出的示例(标识符前后都是下划线),可以用r'_([A-Z0-9]{2})_'来匹配下划线之间的两位字母/数字组合。如果你的文件名格式有变化,直接调整正则即可:
- 若标识符在文件名开头:
r'^([A-Z0-9]{2})_'(比如A1_XYZ_123.pdf) - 若标识符在文件名末尾(.pdf前):
r'_([A-Z0-9]{2})\.pdf$'(比如XYZ_123_A1.pdf)
提取标识符的代码示例:
import os import re pdf_folder = "你的PDF文件夹路径" # 根据你的文件名格式调整正则表达式 identifier_pattern = re.compile(r'_([A-Z0-9]{2})_') for filename in os.listdir(pdf_folder): # 只处理PDF文件,忽略大小写 if filename.lower().endswith(".pdf"): pdf_path = os.path.join(pdf_folder, filename) # 查找匹配的标识符 match = identifier_pattern.search(filename) if match: identifier = match.group(1) print(f"从{filename}提取到标识符:{identifier}") # 接下来匹配邮箱并发送 if identifier in email_map: recipient_email = email_map[identifier] send_email_with_attachment(recipient_email, pdf_path) else: print(f"警告:标识符{identifier}在CSV中未找到对应邮箱") else: print(f"警告:文件{filename}中未找到符合格式的两位标识符")
2.3 发送带PDF附件的邮件
封装一个通用的发邮件函数,替换成你自己的邮箱配置即可:
import smtplib from email.mime.multipart import MIMEMultipart from email.mime.base import MIMEBase from email import encoders from email.mime.text import MIMEText def send_email_with_attachment(recipient_email, pdf_path): # 替换成你的发件邮箱信息 sender_email = "你的发件邮箱@example.com" sender_password = "你的邮箱密码/应用密码" # 比如Gmail需要用应用密码 smtp_server = "smtp.example.com" # 比如smtp.gmail.com,端口587 smtp_port = 587 # 创建邮件对象 msg = MIMEMultipart() msg['From'] = sender_email msg['To'] = recipient_email msg['Subject'] = f"你的PDF文件:{os.path.basename(pdf_path)}" # 添加邮件正文 body = "您好,附件是您需要的PDF文件,请查收。" msg.attach(MIMEText(body, 'plain')) # 添加PDF附件 filename = os.path.basename(pdf_path) with open(pdf_path, "rb") as attachment: part = MIMEBase('application', 'octet-stream') part.set_payload(attachment.read()) encoders.encode_base64(part) part.add_header('Content-Disposition', f'attachment; filename= {filename}') msg.attach(part) # 发送邮件 try: server = smtplib.SMTP(smtp_server, smtp_port) server.starttls() # 开启加密连接 server.login(sender_email, sender_password) server.sendmail(sender_email, recipient_email, msg.as_string()) server.quit() print(f"✅ 邮件已成功发送到{recipient_email}") except smtplib.SMTPAuthenticationError: print(f"❌ 发送失败:邮箱认证错误,请检查用户名和密码") except Exception as e: print(f"❌ 发送到{recipient_email}时出错:{str(e)}")
3. 完整整合脚本
把上面的代码整合起来,加上异常处理和参数配置,方便直接使用:
import os import re import csv import smtplib from email.mime.multipart import MIMEMultipart from email.mime.base import MIMEBase from email import encoders from email.mime.text import MIMEText def load_email_map(csv_path): email_map = {} try: with open(csv_path, mode='r', encoding='utf-8') as file: reader = csv.DictReader(file) if "ID" not in reader.fieldnames or "Email" not in reader.fieldnames: raise ValueError("CSV文件必须包含'ID'和'Email'两列") for row in reader: identifier = row["ID"].strip() email = row["Email"].strip() if identifier and email: email_map[identifier] = email print(f"成功加载{len(email_map)}条ID-邮箱映射") return email_map except FileNotFoundError: print(f"错误:未找到CSV文件{csv_path}") return {} except Exception as e: print(f"加载CSV出错:{str(e)}") return {} def send_email_with_attachment(recipient_email, pdf_path, sender_info): sender_email, sender_pwd, smtp_host, smtp_port = sender_info if not os.path.exists(pdf_path): print(f"错误:PDF文件{pdf_path}不存在") return try: msg = MIMEMultipart() msg['From'] = sender_email msg['To'] = recipient_email msg['Subject'] = f"您的PDF文件:{os.path.basename(pdf_path)}" body = "您好,附件是您需要的PDF文件,请查收。" msg.attach(MIMEText(body, 'plain')) filename = os.path.basename(pdf_path) with open(pdf_path, "rb") as attachment: part = MIMEBase('application', 'octet-stream') part.set_payload(attachment.read()) encoders.encode_base64(part) part.add_header('Content-Disposition', f'attachment; filename= {filename}') msg.attach(part) server = smtplib.SMTP(smtp_host, smtp_port) server.starttls() server.login(sender_email, sender_pwd) server.sendmail(sender_email, recipient_email, msg.as_string()) server.quit() print(f"✅ 邮件已发送到 {recipient_email}") except Exception as e: print(f"❌ 发送到{recipient_email}失败:{str(e)}") def main(): # ---------- 配置参数 ---------- csv_path = "email_mapping.csv" pdf_folder = "pdf_files" sender_info = ( "your_email@example.com", "your_password_or_app_password", "smtp.example.com", 587 ) # 根据你的文件名格式调整正则表达式 identifier_pattern = re.compile(r'_([A-Z0-9]{2})_') # ---------------------------- email_map = load_email_map(csv_path) if not email_map: print("无法加载邮箱映射,脚本终止") return if not os.path.exists(pdf_folder): print(f"错误:PDF文件夹{pdf_folder}不存在") return for filename in os.listdir(pdf_folder): if filename.lower().endswith(".pdf"): pdf_path = os.path.join(pdf_folder, filename) match = identifier_pattern.search(filename) if match: identifier = match.group(1) if identifier in email_map: recipient_email = email_map[identifier] send_email_with_attachment(recipient_email, pdf_path, sender_info) else: print(f"⚠️ 标识符{identifier}(来自{filename})未在CSV中找到对应邮箱") else: print(f"⚠️ 文件{filename}中未找到符合格式的两位标识符") if __name__ == "__main__": main()
4. 注意事项
- 正则调整:一定要根据你的实际文件名格式修改
identifier_pattern,可以先用在线正则工具测试匹配效果; - 邮箱配置:不同邮箱的SMTP设置不同,比如Gmail需要开启两步验证并使用应用密码,QQ邮箱需要在设置里开启POP3/SMTP服务;
- 测试先行:先找几个测试文件和对应的邮箱,验证脚本能正确提取标识符和发送邮件后,再批量处理。
内容的提问来源于stack exchange,提问作者Mike P
相关产品推荐
相关产品推荐

