【python】~实现工具软件:QQ邮件即时、定时发送

发布于:2025-06-30 ⋅ 阅读:(22) ⋅ 点赞:(0)

界面展示:

界面1:邮件设置

在这里插入图片描述

界面2:定时设置

在这里插入图片描述

界面3:发送日志

在这里插入图片描述

AI实现提示词:

发给豆包app:
在这里插入图片描述
把这个程序新增一个UI界面并带有如上功能,让我选择文件并可以设置定时间发送文件,请使用python代码帮我实现。把这个程序新增一个UI界面并带有如上功能,让我选择文件并可以设置定时间发送文件,请使用python代码帮我实现。

实现步骤:

1、新建一个txt文本文件,把如下代码复制进去,然后保存并修改文件后缀名为: .py结尾
(PS: 必须提前安装好python运行行环境)

import tkinter as tk
from tkinter import filedialog, ttk, messagebox
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
import time
import threading
import datetime
import os
from tkinter import font

class EmailSenderApp:
    def __init__(self, root):
        self.root = root
        self.root.title("邮件定时发送工具")
        self.root.geometry("700x600")
        self.root.minsize(600, 500)
        
        # 确保中文显示正常
        self.default_font = font.nametofont("TkDefaultFont")
        self.default_font.configure(family="SimHei", size=10)
        self.root.option_add("*Font", self.default_font)
        
        # 状态和进度 - 提前到界面创建之前初始化
        self.status_var = tk.StringVar(value="就绪")
        self.progress_var = tk.DoubleVar(value=0)
        
        # 邮件配置
        self.email_config = {
            'smtp_server': tk.StringVar(value='smtp.qq.com'),
            'smtp_port': tk.IntVar(value=465),
            'use_ssl': tk.BooleanVar(value=True),
            'sender_email': tk.StringVar(),
            'sender_password': tk.StringVar(),
            'recipient_email': tk.StringVar(),
            'subject': tk.StringVar(value='今日工作总结'),
            'body': tk.StringVar()
        }
        
        # 定时设置
        self.timer_config = {
            'send_now': tk.BooleanVar(value=True),
            'send_at': tk.StringVar(value=self._get_default_time()),
            'file_path': tk.StringVar()
        }
        
        # 创建界面
        self._create_widgets()
        
    def _get_default_time(self):
        # 默认设置为明天早上9点
        tomorrow = datetime.datetime.now() + datetime.timedelta(days=1)
        return tomorrow.strftime("%Y-%m-%d 09:00")
    
    def _create_widgets(self):
        # 创建标签页
        tab_control = ttk.Notebook(self.root)
        
        # 邮件设置标签页
        email_tab = ttk.Frame(tab_control)
        tab_control.add(email_tab, text="邮件设置")
        
        # 定时设置标签页
        timer_tab = ttk.Frame(tab_control)
        tab_control.add(timer_tab, text="定时设置")
        
        # 日志标签页
        log_tab = ttk.Frame(tab_control)
        tab_control.add(log_tab, text="发送日志")
        
        tab_control.pack(expand=1, fill="both")
        
        # === 邮件设置页面 ===
        # SMTP服务器设置
        smtp_frame = ttk.LabelFrame(email_tab, text="SMTP服务器设置")
        smtp_frame.pack(fill="x", padx=10, pady=5)
        
        ttk.Label(smtp_frame, text="SMTP服务器:").grid(row=0, column=0, sticky="w", padx=5, pady=5)
        ttk.Entry(smtp_frame, textvariable=self.email_config['smtp_server']).grid(row=0, column=1, sticky="ew", padx=5, pady=5)
        
        ttk.Label(smtp_frame, text="端口:").grid(row=0, column=2, sticky="w", padx=5, pady=5)
        ttk.Entry(smtp_frame, textvariable=self.email_config['smtp_port'], width=10).grid(row=0, column=3, sticky="w", padx=5, pady=5)
        
        ttk.Checkbutton(smtp_frame, text="使用SSL", variable=self.email_config['use_ssl']).grid(row=0, column=4, sticky="w", padx=5, pady=5)
        
        # 发件人设置
        sender_frame = ttk.LabelFrame(email_tab, text="发件人信息")
        sender_frame.pack(fill="x", padx=10, pady=5)
        
        ttk.Label(sender_frame, text="邮箱:").grid(row=0, column=0, sticky="w", padx=5, pady=5)
        ttk.Entry(sender_frame, textvariable=self.email_config['sender_email']).grid(row=0, column=1, sticky="ew", padx=5, pady=5)
        
        ttk.Label(sender_frame, text="授权码:").grid(row=1, column=0, sticky="w", padx=5, pady=5)
        ttk.Entry(sender_frame, textvariable=self.email_config['sender_password'], show="*").grid(row=1, column=1, sticky="ew", padx=5, pady=5)
        
        # 收件人设置
        recipient_frame = ttk.LabelFrame(email_tab, text="收件人信息")
        recipient_frame.pack(fill="x", padx=10, pady=5)
        
        ttk.Label(recipient_frame, text="收件人邮箱:").grid(row=0, column=0, sticky="w", padx=5, pady=5)
        ttk.Entry(recipient_frame, textvariable=self.email_config['recipient_email']).grid(row=0, column=1, sticky="ew", padx=5, pady=5)
        
        # 邮件内容设置
        content_frame = ttk.LabelFrame(email_tab, text="邮件内容")
        content_frame.pack(fill="both", expand=True, padx=10, pady=5)
        
        ttk.Label(content_frame, text="主题:").grid(row=0, column=0, sticky="w", padx=5, pady=5)
        ttk.Entry(content_frame, textvariable=self.email_config['subject']).grid(row=0, column=1, sticky="ew", padx=5, pady=5)
        
        ttk.Label(content_frame, text="正文:").grid(row=1, column=0, sticky="nw", padx=5, pady=5)
        self.body_text = tk.Text(content_frame, height=10, width=50)
        self.body_text.grid(row=1, column=1, sticky="nsew", padx=5, pady=5)
        
        # 配置列和行的权重,使文本区域可以扩展
        content_frame.columnconfigure(1, weight=1)
        content_frame.rowconfigure(1, weight=1)
        
        # === 定时设置页面 ===
        timer_frame = ttk.LabelFrame(timer_tab, text="发送选项")
        timer_frame.pack(fill="x", padx=10, pady=5)
        
        ttk.Radiobutton(timer_frame, text="立即发送", variable=self.timer_config['send_now'], value=True).grid(row=0, column=0, sticky="w", padx=5, pady=5)
        ttk.Radiobutton(timer_frame, text="定时发送", variable=self.timer_config['send_now'], value=False).grid(row=0, column=1, sticky="w", padx=5, pady=5)
        
        time_frame = ttk.LabelFrame(timer_tab, text="定时设置 (YYYY-MM-DD HH:MM)")
        time_frame.pack(fill="x", padx=10, pady=5)
        
        ttk.Entry(time_frame, textvariable=self.timer_config['send_at']).pack(fill="x", padx=5, pady=5)
        
        file_frame = ttk.LabelFrame(timer_tab, text="附件选择")
        file_frame.pack(fill="x", padx=10, pady=5)
        
        ttk.Entry(file_frame, textvariable=self.timer_config['file_path']).grid(row=0, column=0, sticky="ew", padx=5, pady=5)
        ttk.Button(file_frame, text="浏览文件", command=self._browse_file).grid(row=0, column=1, sticky="e", padx=5, pady=5)
        
        file_frame.columnconfigure(0, weight=1)
        
        # === 日志页面 ===
        log_frame = ttk.LabelFrame(log_tab, text="发送日志")
        log_frame.pack(fill="both", expand=True, padx=10, pady=5)
        
        self.log_text = tk.Text(log_frame, height=10, width=50)
        self.log_text.pack(fill="both", expand=True, padx=5, pady=5)
        self.log_text.config(state=tk.DISABLED)
        
        # === 底部状态栏和按钮 ===
        status_frame = ttk.Frame(self.root)
        status_frame.pack(fill="x", side="bottom", padx=10, pady=5)
        
        ttk.Label(status_frame, textvariable=self.status_var).pack(side="left")
        
        ttk.Progressbar(status_frame, variable=self.progress_var, length=200).pack(side="right")
        
        button_frame = ttk.Frame(self.root)
        button_frame.pack(fill="x", side="bottom", padx=10, pady=5)
        
        ttk.Button(button_frame, text="发送邮件", command=self._send_email).pack(side="right", padx=5)
        ttk.Button(button_frame, text="保存设置", command=self._save_settings).pack(side="right", padx=5)
        
    def _browse_file(self):
        filename = filedialog.askopenfilename(
            title="选择文件",
            filetypes=[("所有文件", "*.*"), ("文本文件", "*.txt"), ("Word文档", "*.docx")]
        )
        if filename:
            self.timer_config['file_path'].set(filename)
    
    def _log(self, message):
        self.log_text.config(state=tk.NORMAL)
        self.log_text.insert(tk.END, f"{datetime.datetime.now().strftime('%H:%M:%S')} - {message}\n")
        self.log_text.see(tk.END)
        self.log_text.config(state=tk.DISABLED)
    
    def _save_settings(self):
        # 从文本框更新正文内容
        self.email_config['body'].set(self.body_text.get("1.0", tk.END).strip())
        
        try:
            with open('email_settings.ini', 'w', encoding='utf-8') as f:
                f.write(f"smtp_server={self.email_config['smtp_server'].get()}\n")
                f.write(f"smtp_port={self.email_config['smtp_port'].get()}\n")
                f.write(f"use_ssl={self.email_config['use_ssl'].get()}\n")
                f.write(f"sender_email={self.email_config['sender_email'].get()}\n")
                f.write(f"recipient_email={self.email_config['recipient_email'].get()}\n")
                f.write(f"subject={self.email_config['subject'].get()}\n")
                f.write(f"body={self.email_config['body'].get()}\n")
                f.write(f"send_at={self.timer_config['send_at'].get()}\n")
                f.write(f"file_path={self.timer_config['file_path'].get()}\n")
            self._log("设置已保存")
            messagebox.showinfo("成功", "设置已保存到 email_settings.ini")
        except Exception as e:
            self._log(f"保存设置失败: {str(e)}")
            messagebox.showerror("错误", f"保存设置失败: {str(e)}")
    
    def _load_settings(self):
        try:
            if os.path.exists('email_settings.ini'):
                with open('email_settings.ini', 'r', encoding='utf-8') as f:
                    lines = f.readlines()
                    settings = {}
                    for line in lines:
                        key, value = line.strip().split('=', 1)
                        settings[key] = value
                
                # 恢复设置
                self.email_config['smtp_server'].set(settings.get('smtp_server', ''))
                self.email_config['smtp_port'].set(int(settings.get('smtp_port', 465)))
                self.email_config['use_ssl'].set(settings.get('use_ssl', 'True') == 'True')
                self.email_config['sender_email'].set(settings.get('sender_email', ''))
                self.email_config['recipient_email'].set(settings.get('recipient_email', ''))
                self.email_config['subject'].set(settings.get('subject', ''))
                self.email_config['body'].set(settings.get('body', ''))
                self.timer_config['send_at'].set(settings.get('send_at', self._get_default_time()))
                self.timer_config['file_path'].set(settings.get('file_path', ''))
                
                # 更新文本框内容
                self.body_text.delete("1.0", tk.END)
                self.body_text.insert(tk.END, self.email_config['body'].get())
                
                self._log("设置已加载")
        except Exception as e:
            self._log(f"加载设置失败: {str(e)}")
    
    def _send_email(self):
        # 从文本框更新正文内容
        self.email_config['body'].set(self.body_text.get("1.0", tk.END).strip())
        
        # 验证输入
        if not self.email_config['sender_email'].get():
            messagebox.showerror("错误", "请输入发件人邮箱")
            return
        
        if not self.email_config['sender_password'].get():
            messagebox.showerror("错误", "请输入发件人授权码")
            return
        
        if not self.email_config['recipient_email'].get():
            messagebox.showerror("错误", "请输入收件人邮箱")
            return
        
        # 如果选择定时发送,验证时间格式
        if not self.timer_config['send_now'].get():
            try:
                send_time = datetime.datetime.strptime(self.timer_config['send_at'].get(), "%Y-%m-%d %H:%M")
                if send_time < datetime.datetime.now():
                    messagebox.showerror("错误", "发送时间不能早于当前时间")
                    return
            except ValueError:
                messagebox.showerror("错误", "时间格式不正确,请使用 YYYY-MM-DD HH:MM 格式")
                return
        
        # 更新状态
        self.status_var.set("准备发送...")
        self._log("开始处理邮件发送请求")
        
        # 在单独线程中执行发送任务
        threading.Thread(target=self._send_email_thread, daemon=True).start()
    
    def _send_email_thread(self):
        try:
            # 如果选择定时发送,等待到指定时间
            if not self.timer_config['send_now'].get():
                send_time = datetime.datetime.strptime(self.timer_config['send_at'].get(), "%Y-%m-%d %H:%M")
                wait_seconds = (send_time - datetime.datetime.now()).total_seconds()
                
                self._log(f"等待中,将于 {self.timer_config['send_at'].get()} 发送邮件")
                self.status_var.set(f"等待中,将于 {self.timer_config['send_at'].get()} 发送")
                
                # 分段等待,以便可以更新进度条
                while wait_seconds > 0:
                    time.sleep(1)
                    wait_seconds -= 1
                    progress = 100 - (wait_seconds / (send_time - datetime.datetime.now()).total_seconds() * 100)
                    self.progress_var.set(progress)
                    self.status_var.set(f"等待中: {int(progress)}%")
            
            # 开始发送邮件
            self._log("读取今日小结文档中")
            self.progress_var.set(20)
            self.status_var.set("读取文档中...")
            
            # 准备邮件内容
            msg = MIMEMultipart()
            msg['From'] = self.email_config['sender_email'].get()
            msg['To'] = self.email_config['recipient_email'].get()
            msg['Subject'] = self.email_config['subject'].get()
            
            # 添加正文
            msg.attach(MIMEText(self.email_config['body'].get(), 'plain', 'utf-8'))
            
            # 添加附件
            file_path = self.timer_config['file_path'].get()
            if file_path and os.path.exists(file_path):
                with open(file_path, 'rb') as f:
                    attachment = MIMEApplication(f.read(), _subtype=os.path.splitext(file_path)[1][1:])
                    attachment.add_header('Content-Disposition', 'attachment', filename=os.path.basename(file_path))
                    msg.attach(attachment)
                self._log(f"已添加附件: {os.path.basename(file_path)}")
            else:
                self._log("未选择附件")
            
            self._log("正在编写邮件正文")
            self.progress_var.set(50)
            self.status_var.set("编写邮件正文...")
            
            # 连接SMTP服务器并发送邮件
            self._log(f"正在连接到 SMTP 服务器: {self.email_config['smtp_server'].get()}")
            if self.email_config['use_ssl'].get():
                server = smtplib.SMTP_SSL(self.email_config['smtp_server'].get(), self.email_config['smtp_port'].get())
            else:
                server = smtplib.SMTP(self.email_config['smtp_server'].get(), self.email_config['smtp_port'].get())
                server.starttls()  # 使用TLS加密
            
            self.progress_var.set(70)
            self.status_var.set("正在登录邮箱...")
            
            self._log(f"正在使用邮箱 {self.email_config['sender_email'].get()} 登录")
            server.login(self.email_config['sender_email'].get(), self.email_config['sender_password'].get())
            
            self.progress_var.set(80)
            self.status_var.set("正在发送邮件...")
            
            self._log(f"正在发送给: {self.email_config['recipient_email'].get()}")
            server.sendmail(
                self.email_config['sender_email'].get(),
                self.email_config['recipient_email'].get(),
                msg.as_string()
            )
            
            server.quit()
            
            # 完成发送
            self.progress_var.set(100)
            self.status_var.set("邮件发送成功!")
            self._log("邮件发送成功!下班愉快!")
            
            # 提示用户
            self.root.after(0, lambda: messagebox.showinfo("成功", "邮件发送成功!"))
            
        except Exception as e:
            self.progress_var.set(0)
            self.status_var.set(f"发送失败: {str(e)}")
            self._log(f"发送失败: {str(e)}")
            self.root.after(0, lambda: messagebox.showerror("错误", f"发送失败: {str(e)}"))

if __name__ == "__main__":
    root = tk.Tk()
    app = EmailSenderApp(root)
    
    # 尝试加载保存的设置
    app._load_settings()
    
    root.mainloop()    

2、运行此python文件:
打开电脑上的powershell窗口,输入:python + 空格 + 此文件电脑存放路径,然后按一下回车:
如下:
在这里插入图片描述
运行成功!!!
运行成功后,我们去QQ邮箱官网:https://mail.qq.com/
登录上自己的邮箱之后,去获取【授权码】:
在这里插入图片描述
在这里插入图片描述
往下找到并点击【继续获取授权码】:
在这里插入图片描述
使用手机微信扫码发送信息之后,点击【我已发送】
在这里插入图片描述
之后,弹窗就可以获取到授权码了。复制粘贴到python程序界面中的【授权码】:
如下填写后。再点击【发送邮件】即可
在这里插入图片描述

功能介绍:

这是一个功能完整的邮件定时发送工具,具有以下特点:

  1. 美观易用的图形界面,采用标签页设计,分为邮件设置、定时设置和发送日志三个部分
  2. 完整的邮件配置选项,包括 SMTP 服务器设置、发件人和收件人信息、邮件主题和正文
  3. 灵活的定时发送功能,可以选择立即发送或指定未来的日期和时间发送
  4. 文件选择功能,支持添加附件
  5. 发送进度显示和日志记录,方便跟踪邮件发送状态
  6. 设置保存和加载功能,下次打开程序时可以恢复之前的配置

使用方法:

  1. 填写邮件服务器信息、发件人和收件人邮箱
  2. 输入邮件主题和正文
  3. 选择是否立即发送或定时发送
  4. 如果需要,选择要附加的文件
  5. 点击 “发送邮件” 按钮开始发送

注意:

  • 程序会保存设置到 email_settings.ini 文件,下次启动时会自动加载
  • 对于 QQ 邮箱等需要授权码的邮箱,需要先在邮箱设置中开启 SMTP 服务并获取授权码
  • 程序会在日志标签页中记录所有操作和状态信息,方便排查问题

网站公告

今日签到

点亮在社区的每一天
去签到