Python邮件批量发送工具:函数间变量传递问题求助
解决Python邮件广播工具中函数间变量共享问题
问题根源
你遇到的核心问题是:browse函数中生成的recemail是局部变量,submit函数无法直接访问;调用browse()获取变量会重复触发文件选择窗口,因为该函数执行时会先弹出选择框。另外代码中ini_list未定义,运行时会抛出未定义错误。
解决方案1:正确使用全局变量
在全局作用域初始化需要共享的变量,然后在函数内部用global声明要修改的全局变量,这样submit就能直接访问这些变量:
from tkinter import * from tkinter import filedialog # 补充原代码缺失的导入 import tkinter.messagebox as msg import smtplib as smtp import csv from itertools import chain # 全局初始化共享变量 recemail = [] ini_list = [] # 读取CSV文件的browse函数 def browse(): global recemail, ini_list # 声明要修改的全局变量 file_path=filedialog.askopenfilename(title="Open CSV file") ini_list.clear() # 每次选择文件清空旧数据,避免重复累加 with open(file_path) as csvfile: read = csv.reader(csvfile) for row in read: ini_list.append(row) flatten_list = list(chain.from_iterable(ini_list)) recemail = list(flatten_list) # 显示选中的文件路径 Label(window,text=file_path, border=0, bg='#BAE1E3',font="inter 10", fg="grey").place(x=330,y=230) # 发邮件函数 def submit(): # 先检查是否已选择收件人列表 if not recemail: msg.showwarning("提示", "请先选择包含收件人邮箱的CSV文件") return try: email = login_email.get() pass_word = login_pass.get() subject = email_subject.get() body = email_body.get("1.0", END).strip() # Text组件的内容获取方式 server = smtp.SMTP("smtp.gmail.com",587) server.starttls() server.ehlo() server.login(email,pass_word) message = f"subject:{subject}\n\n{body}" # 修正拼写错误:massage → message server.sendmail(email, recemail, message) server.quit() msg.showinfo("状态","邮件已成功发送到目标列表。感谢使用!") except smtp.SMTPAuthenticationError: msg.showwarning("错误","SMTP认证失败,请检查邮箱和密码是否正确(Gmail需开启应用专用密码)") except Exception as e: msg.showwarning("错误", f"发送失败:{str(e)}") # 初始化窗口和界面元素示例 window = Tk() login_email = StringVar() login_pass = StringVar() email_subject = StringVar() email_body = Text(window, width=50, height=10) # 创建按钮组件 Button(window, text="选择CSV文件", command=browse).place(x=100, y=230) Button(window, text="发送邮件", command=submit).place(x=100, y=300) window.mainloop()
解决方案2:用类封装(更规范的方式)
避免全局变量的混乱,将界面元素和共享数据封装到类中,通过self在方法间共享变量:
from tkinter import * from tkinter import filedialog import tkinter.messagebox as msg import smtplib as smtp import csv from itertools import chain class EmailBroadcaster: def __init__(self, root): self.root = root self.recemail = [] self.ini_list = [] # 初始化界面组件 self.login_email = StringVar() self.login_pass = StringVar() self.email_subject = StringVar() # 创建输入框 Label(root, text="登录邮箱:").place(x=50, y=50) Entry(root, textvariable=self.login_email).place(x=150, y=50) Label(root, text="登录密码:").place(x=50, y=100) Entry(root, textvariable=self.login_pass, show="*").place(x=150, y=100) Label(root, text="邮件主题:").place(x=50, y=150) Entry(root, textvariable=self.email_subject).place(x=150, y=150) Label(root, text="邮件内容:").place(x=50, y=200) self.email_body = Text(root, width=50, height=10) self.email_body.place(x=150, y=200) # 创建按钮 Button(root, text="选择收件人CSV", command=self.browse).place(x=50, y=350) Button(root, text="批量发送邮件", command=self.submit).place(x=200, y=350) def browse(self): file_path=filedialog.askopenfilename(title="Open CSV file") self.ini_list.clear() with open(file_path) as csvfile: read = csv.reader(csvfile) for row in read: self.ini_list.append(row) flatten_list = list(chain.from_iterable(self.ini_list)) self.recemail = list(flatten_list) # 显示选中的文件路径 Label(self.root, text=file_path, border=0, bg='#BAE1E3', font="inter 10", fg="grey").place(x=330,y=230) def submit(self): if not self.recemail: msg.showwarning("提示", "请先选择包含收件人邮箱的CSV文件") return try: email = self.login_email.get() pass_word = self.login_pass.get() subject = self.email_subject.get() body = self.email_body.get("1.0", END).strip() server = smtp.SMTP("smtp.gmail.com",587) server.starttls() server.ehlo() server.login(email, pass_word) message = f"subject:{subject}\n\n{body}" server.sendmail(email, self.recemail, message) server.quit() msg.showinfo("状态","邮件已成功发送到目标列表。感谢使用!") except smtp.SMTPAuthenticationError: msg.showwarning("错误","SMTP认证失败,请检查邮箱和密码是否正确(Gmail需开启应用专用密码)") except Exception as e: msg.showwarning("错误", f"发送失败:{str(e)}") # 启动应用 if __name__ == "__main__": root = Tk() root.title("邮件广播工具") app = EmailBroadcaster(root) root.mainloop()
额外注意事项
- 原代码缺少
filedialog的导入,需补充from tkinter import filedialog - 若使用Gmail发送邮件,需开启应用专用密码(需先启用两步验证)
- 避免使用宽泛的
except,捕获具体异常能提供更精准的错误提示 - 若
email_body是Text组件,需用get("1.0", END)获取内容,而不是get()
内容的提问来源于stack exchange,提问作者Abdul Rehman
相关产品推荐
相关产品推荐

