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

re.compile未匹配指定正则模式时如何自动发信至指定邮箱?

实现思路
  • 提前把正则表达式编译逻辑移到邮件遍历循环外,避免每处理一封邮件就重复编译正则,减少不必要的性能消耗。
  • 为每封待处理邮件新增匹配状态标记,初始值设为未匹配。遍历邮件正文提取到正则匹配项时,除了将匹配结果写入csv文件,同时将标记更新为已匹配。
  • 单封邮件的内容解析、正则匹配流程全部跑完后,检查匹配状态标记:如果仍为未匹配状态,就通过SMTP协议将原始邮件原封不动转发到指定邮箱。
  • 转发时直接复用原始邮件的完整RFC822内容,避免手动拼接主题、正文导致附件、邮件头信息丢失。
调整后可直接运行的代码
import imaplib
import email
from email.header import decode_header
import csv
import re
import smtplib
from email.message import Message

# -------------------------- 配置项 请自行修改 --------------------------
IMAP_SERVER = "你的imap服务器地址,比如imap.qq.com"
EMAIL_ACCOUNT = "你的邮箱账号"
EMAIL_PASSWORD = "你的邮箱第三方授权码/登录密码"
TARGET_FORWARD_EMAIL = "未匹配邮件要转发到的目标邮箱地址"
SEARCH_MAIL_COUNT = N  # 替换为原代码中的N值,即要遍历的最近N封邮件
# ----------------------------------------------------------------------

# 提前编译正则,无需在循环内重复编译
pattern = re.compile(
    r"([a-zA-Z]+[0-9]+) Line ([0-9]+) Seq ([0-9]) ([0-9]+/[0-9]+/[0-9]+)")

# 初始化IMAP连接
imap = imaplib.IMAP4_SSL(IMAP_SERVER)
imap.login(EMAIL_ACCOUNT, EMAIL_PASSWORD)
imap.select("INBOX")
# 获取收件箱邮件总数,兼容原代码逻辑
res, messages_data = imap.search(None, "ALL")
messages = int(messages_data[0].split()[-1])

with open("data.csv", "w", newline="", encoding="utf-8") as f_out:
    writer = csv.writer(f_out)
    # 可根据自身需求决定是否保留csv表头
    writer.writerow(["标识字段", "行号", "序列值", "日期"])

    for i in range(messages, messages - SEARCH_MAIL_COUNT, -1):
        res, msg_data = imap.fetch(str(i), "(RFC822)")
        for response in msg_data:
            if not isinstance(response, tuple):
                continue
            # 保留邮件原始字节内容,用于后续转发
            raw_email = response[1]
            msg = email.message_from_bytes(raw_email)
            
            # 解码邮件头,兼容多编码场景
            subject, encoding = decode_header(msg["Subject"])[0]
            if isinstance(subject, bytes):
                subject = subject.decode(encoding if encoding else "utf-8", errors="replace")
            from_addr, encoding = decode_header(msg.get("From"))[0]
            if isinstance(from_addr, bytes):
                from_addr = from_addr.decode(encoding if encoding else "utf-8", errors="replace")
            print("Subject:", subject)
            print("From:", from_addr)

            # 初始化当前邮件的匹配状态为未匹配
            has_match = False

            # 遍历邮件内容块
            for part in msg.walk():
                payload = part.get_payload(decode=True)
                if payload is None:
                    continue
                # 自动识别邮件编码解码,避免乱码报错
                charset = part.get_content_charset()
                body = payload.decode(charset if charset else "utf-8", errors="replace")

                matches = list(pattern.finditer(body))
                if matches:
                    has_match = True
                    writer.writerows(map(lambda m: m.groups(), matches))
                # 保留原有逻辑:匹配到第一个文本块就跳出循环
                break

            # 新增转发逻辑:当前邮件无任何匹配项时执行转发
            if not has_match:
                forward_msg = Message()
                forward_msg["From"] = EMAIL_ACCOUNT
                forward_msg["To"] = TARGET_FORWARD_EMAIL
                forward_msg["Subject"] = f"[转发未匹配规则邮件] 原主题:{subject}"
                forward_msg.set_payload(raw_email)

                # 连接SMTP服务发送邮件
                with smtplib.SMTP_SSL(IMAP_SERVER, 465) as smtp:
                    smtp.login(EMAIL_ACCOUNT, EMAIL_PASSWORD)
                    smtp.send_message(forward_msg, from_addr=EMAIL_ACCOUNT, to_addrs=TARGET_FORWARD_EMAIL)
                print(f"邮件《{subject}》未匹配规则,已转发到指定邮箱")

imap.close()
imap.logout()
注意事项
  • 代码已补全编码兼容处理,解决原代码直接调用decode()遇到非UTF-8编码邮件时的报错问题。
  • 如果需要匹配邮件所有文本块(比如多段正文、嵌套转发邮件内容),可以删除内容遍历循环里的break,等所有part遍历完成后再判断匹配状态即可。
  • 不同邮箱服务商的SMTP端口可能存在差异,如果465端口连接失败,可以尝试替换为25、587端口,对应调整SMTP连接方式。
  • 邮箱登录建议使用专门的第三方服务授权码,不要直接使用账号登录密码,避免账号安全风险。

内容的提问来源于stack exchange,提问作者LaunchCoder33

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 10:42:50