循环匹配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()
问题根源
- 全局变量滥用:
regex、html_file、count都是全局变量,生成文件时会不断覆盖这些变量的值,最终只保留最后一组文件的相关数据。发送邮件时直接引用这些全局变量,自然只会发送最后一组的内容。 - 邮件发送逻辑混乱:遍历文件时每次都定义
sendmail函数,且没有根据当前遍历的文件编号匹配对应数据,反而依赖全局变量的残留值,导致所有邮件都复用最后一次生成的regex、html_file和count。 - 重复处理文件:遍历文件时同时处理
.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
相关产品推荐
相关产品推荐

