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

循环匹配txt/html文件对发送邮件时重复发送最后一组的问题排查

问题排查:邮件重复发送最后一组文件对

我用两个函数分别生成了signal1.txt、signal2.txt等文本文件,以及signal1.html、signal2.html等HTML文件,需要为每一组同编号的文件对发送对应邮件。但多次尝试后,始终重复发送最后一组文件对,单类型文件发送无问题。相关代码如下:

数据来源(Counter模块处理)

data = Counter({('A user account was locked out ', 47, 'medium', 25): 1, ('An attempt was made to reset an accounts password ', 73, 'high', 2): 1, ('PowerShell Keylogging Script', 73, 'high', 37): 1, ('PowerShell Suspicious Script with Audio Capture Capabilities', 47, 'medium', 36): 1})

生成TXT文件的函数

def create_txt_files():
    global regex
    global count
    count = 0

    #Convert dict into string and remove unwanted chars
    for signal in dict(event_dict).keys():
        indiv_signal = (str(signal).replace(",",'').replace('(','').replace(')','')\
                        .replace("'",'').replace('[','').replace(']',''))
        #Further removal of debris using regex
        pattern = '(^\\D*)'
        regex = ''.join(re.findall(pattern,indiv_signal,re.MULTILINE))
        count +=1
        with open(f"signal{count}.txt", "w") as fh:
            fh.write(str(regex))
create_txt_files()

生成HTML文件的函数

#Create Individual HTML files
def create_indiv_html_files():
    global html_file
    global count
    count = 0

    #Turn rows into columns
    for items in list(event_dict):
        df = pd.DataFrame(items)
        new_df = df.transpose()
        new_df.columns = ['Alert','Score Risk','Severity','Total']
        html_file = new_df.to_html()
        print(new_df)
        count +=1
        with open(f'signal{count}.html','w') as wf:
            wf.write(html_file)
create_indiv_html_files()

邮件发送函数

from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email import encoders
import smtplib, ssl
import os

dirname = r'C:\Path\To\Files'
ext = ('.txt','html')

for files in os.scandir(dirname):
    if files.path.endswith(ext):

        def sendmail():
            html_body = '''
            <html>
                <body>
                    <p style="font-size: 12;"> <strong>Alert</strong><br>{html_file}</p>
                </body>
            </html>
            '''.format(html_file=html_file)

            subject = f'Alert: {regex} '
            senders_email = 'mail@mail.comt'
            receiver_email = 'mail@mail.comt'

            # Create a multipart message and set headers
            message = MIMEMultipart('alternative')
            message['From'] = senders_email
            message['To'] = receiver_email
            message['Subject'] = subject

            #Attach email body
            message.attach(MIMEText(html_body, 'html'))

            # Name of the file to be attached
            filename = f'signal{count}.html'

            # Open file in binary mode
            with open(filename, 'rb') as attachment:
                # Add file as application/octet-stream
                part = MIMEBase('application', 'octet-stream')
                part.set_payload(attachment.read())

            # Encodes file in ASCII characters to send via email
            encoders.encode_base64(part)

            # Add header as key/value pair to attachment part
            part.add_header(
                'Content-Disposition',
                f"attachment; filename= {filename}",

            )

            # Add attachment to message and convert message to string
            message.attach(part)
            text = message.as_string()

            # Log into server using secure connection
            context = ssl.create_default_context()
            with smtplib.SMTP("smtp.mail.com", 25) as server:
                # server.starttls(context=context)
                # server.login(senders_email, 'password')
                server.sendmail(senders_email, receiver_email, text)
            print("Email sent!")
        sendmail()

问题根源

  1. 全局变量滥用:regex、html_file、count都是全局变量,生成文件时会不断覆盖这些变量的值,最终只保留最后一组文件的相关数据。发送邮件时直接引用这些全局变量,自然只会发送最后一组的内容。
  2. 邮件发送逻辑混乱:遍历文件时每次都定义sendmail函数,且没有根据当前遍历的文件编号匹配对应数据,反而依赖全局变量的残留值,导致所有邮件都复用最后一次生成的regex、html_file和count。
  3. 重复处理文件:遍历文件时同时处理.txt和.html,会导致每个编号的文件对触发两次邮件发送,且内容均为最后一组。

修复方案

1. 移除全局变量,用局部列表存储每组数据

生成文件时,将每组的regex和HTML内容存入列表,方便后续发送邮件时对应取用:

修改后的TXT生成函数

def create_txt_files():
    regex_list = []
    count = 0
    for signal in dict(event_dict).keys():
        indiv_signal = (str(signal).replace(",",'').replace('(','').replace(')','')\
                        .replace("'",'').replace('[','').replace(']',''))
        pattern = '(^\\D*)'
        regex = ''.join(re.findall(pattern,indiv_signal,re.MULTILINE))
        regex_list.append(regex)
        count +=1
        with open(f"signal{count}.txt", "w") as fh:
            fh.write(str(regex))
    return regex_list
regex_list = create_txt_files()

修改后的HTML生成函数

def create_indiv_html_files():
    html_list = []
    count = 0
    for items in list(event_dict):
        df = pd.DataFrame(items)
        new_df = df.transpose()
        new_df.columns = ['Alert','Score Risk','Severity','Total']
        html_content = new_df.to_html()
        html_list.append(html_content)
        count +=1
        with open(f'signal{count}.html','w') as wf:
            wf.write(html_content)
    return html_list
html_list = create_indiv_html_files()

2. 重构邮件发送逻辑,按编号匹配对应内容

不再遍历所有文件,而是根据生成的文件数量,按编号逐一发送对应邮件,确保每组数据和文件严格对应:

from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email import encoders
import smtplib, ssl
import os

dirname = r'C:\Path\To\Files'
senders_email = 'mail@mail.comt'
receiver_email = 'mail@mail.comt'

# 获取文件组数(与生成的文件数量一致)
total_signals = len(regex_list)

def sendmail(signal_num, regex_content, html_content):
    html_body = '''
    <html>
        <body>
            <p style="font-size: 12;"> <strong>Alert</strong><br>{html_content}</p>
        </body>
    </html>
    '''.format(html_content=html_content)

    subject = f'Alert: {regex_content} '

    # 创建多部分消息并设置头部
    message = MIMEMultipart('alternative')
    message['From'] = senders_email
    message['To'] = receiver_email
    message['Subject'] = subject

    # 添加邮件正文
    message.attach(MIMEText(html_body, 'html'))

    # 附加HTML文件
    filename = f'signal{signal_num}.html'
    file_path = os.path.join(dirname, filename)
    with open(file_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}",
    )
    message.attach(part)

    # 附加TXT文件
    txt_filename = f'signal{signal_num}.txt'
    txt_file_path = os.path.join(dirname, txt_filename)
    with open(txt_file_path, 'rb') as txt_attachment:
        txt_part = MIMEBase('application', 'octet-stream')
        txt_part.set_payload(txt_attachment.read())

    encoders.encode_base64(txt_part)
    txt_part.add_header(
        'Content-Disposition',
        f"attachment; filename= {txt_filename}",
    )
    message.attach(txt_part)

    text = message.as_string()

    # 发送邮件
    context = ssl.create_default_context()
    with smtplib.SMTP("smtp.mail.com", 25) as server:
        # server.starttls(context=context)
        # server.login(senders_email, 'password')
        server.sendmail(senders_email, receiver_email, text)
    print(f"第{signal_num}组邮件发送完成!")

# 循环发送每组邮件
for i in range(total_signals):
    sendmail(i+1, regex_list[i], html_list[i])

3. 关键改进点

  • 用局部变量列表存储每组的regex和HTML内容,避免全局变量覆盖
  • 按编号逐一发送邮件,确保每组数据和文件严格对应
  • 单次邮件同时附加同编号的TXT和HTML文件,符合需求且避免重复发送

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 10:55:51