You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在文件名中识别两位标识符并自动发送对应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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:16:35