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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 06:35:26