python应用工具开发:邮件发送GUI程序V1.0

一,开发需求和思路

1.开发需求

你是不是有这么一种需求:在使用邮箱(qq邮箱或163邮箱)时,许多时候都需要我们重新登录(或者隔一段时间),那么如果忘记密码,重新设置将是一件很痛苦的事,加之,我们对邮箱使用很频繁,能不能有种产品能使我们不用登入账户,同时桌面应用程序那样而不用去登入网页版邮箱网站,从而满足我们的发送邮件的基本功能实现呢?答案是有的!
在开源IT时代,我们有很多方法和工具来实现我们的需求,作为极客,我们可以发现SMTP协议背后的一种特殊的发送邮件过程:基于邮箱服务商服务器(IMAP,SMTP,POS3等)来绑定对应程序,从而达到免登录,二次程序开发实现邮件发送功能(简单的理解下就可以了,可以自行百度)。
文末附上这个项目的GitHub地址链接!

2.开发思路

python是具有强大第三方库的一门超级语言,我们可以选择简单且易上手的第三方库!经过笔者比对发现python的yagmail库是个不错的选择,基本配置简单且不复杂!
另外,我们的需求开发出的是产品级,那么就不能再运行时再打开代码,我们要设计出有UI交互界面的程序,由于python自带tkinter库,我们可以用来GUI开发比较方便简单。我们还可以添加程序窗口图标,添加自己喜爱的图片作为背景!
为了使程序成品能给更多用户使用,同时保证各自邮箱的安全性,我们在配置个人邮箱隐私信息时,使用的是本地手动写入配置文件ini,这样使程序成品有可移植性,并且,可以随时修改自己的邮箱配置信息!

3.前期准备

知识储备备注
面向对象编程:类和对象使用类,能使程序二次开发和维护更好,并且程序代码模块化和结构明了,利于阅读和开发
GUI开发tkinterpython自带的tkinterGUI编写,虽然总体UI界面不比主流美观,但是开发简单,且外观逻辑上能满足我们的需求
pyinstallerpython常见且流行的打包程序库,需要下载安装
yagmail库非常好用简单的第三方库,需要下载安装
configparser 库用来管理配置文件的库,需要下载安装
PIL库通用名为Pillow 库,需要下载安装
datetime库用来获取时间 ,需要下载安装
calendar库用来生成日历形式的库
tkinter.filedialog 模块tk库里的文件选择框模块
其他媒体文件用于背景和图标等,看自己选择,可自由决定
邮箱网站取得密钥和其他信息如果没有这些配置,邮箱程序将无法运行,务必设置好先
邮箱网站配置方法如下:
python-基于yagmail库开发自动邮件发送程序

二,编写代码

1.代码模块

(1)MAIL.py

该MAIL.py文件主要放置MAIL类,储存主要的账户配置!

import yagmail#邮箱发送程序的核心库
import configparser#用来管理配置文件的库
import os
class MAIL:#邮箱MAIL类,储存主要的账户配置
    def __init__(self):
        # yagmail库基本参数设置
        self.config = configparser.ConfigParser()
        self.config.read('MailConfig.ini')#读取配置文件,程序打开前需保证该文件存在打开,程序后按相应功能可重新生成初始化配置文件
        user = self.config['DEFAULT']['user']  # 对应自己的邮箱账号
        password =self.config['DEFAULT']['password'] # 对应自己邮箱申请的服务密码,博客有介绍步骤的链接,不是自己邮箱的登录密码
        port = self.config['DEFAULT']['port'] # 邮箱服务器端口
        host = self.config['DEFAULT']['host'] # 对应自己邮箱服务的服务器地址
        self.mail = yagmail.SMTP(user, password, host, port)  # yagmail库初始化实例
        #为了保证程序代码的安全性和移植性,在程序同目录下,打开配置文件(手动或程序功能上打开),填写好配置信息即可
    def creatconfig(self):#恢复成默认的配置文件的方法
        self.config['DEFAULT'] = {'user': 'user',
                             'password': 'password',
                             'port': 'port',
                             'host': 'hosts'
                             }
        with open('MailConfig.ini', 'w+') as configfile:#向配置文件写入默认配置,相当恢复出厂设置!
            self.config.write(configfile)

    def openconfig(self):#程序上自动打开配置文件的方法
        os.startfile('MailConfig.ini')

(2)MAILGUI.py

该MAILGUI.py文件(是主程序)主要放置MAILGUI类,MAILGUI类主要是GUI编写的类和导入并使用前面的MAIL类的方法。

from tkinter import * #tkinter编写的GUI程序
from PIL import Image,ImageTk #由于我们设置窗口图片背景,所以要引入pil库,对应的通用库名为Pillow 库
from MAIL import MAIL #需要导入MAIL类
import datetime #用来获取时间
import calendar #用来生成日历形式的库
import tkinter.filedialog #tk库里的文件选择框模块
class MAILGUI(MAIL):#继承自MAIL类
    def __init__(self):
        super().__init__()
        # 主窗口设置
        self.root = Tk()  # 程序主窗体
        self.root.title('基于SMTP协议自动发送的邮箱程序')  # 设置窗口标题
        self.root.geometry('800x600+300+100')  # 设置窗口大小和在系统显示下的位置
        self.root.iconbitmap('mail.ico')  # 设置窗体图标
        self.lists=[''] #由于后面以第一个列表元素作为显示,所以初始元素先设置为空字符串
        self.filename = '' #初始化附件地址变量

        photo1=Image.open('background1.png')#同代码文件目录下的图片文件,用于日历背景
        self.background_image1 = ImageTk.PhotoImage(photo1.resize((500, 400)))

        # GUI组件
        # 收件人提示标签
        to_label = Label(self.root, text='收件人:', font=('黑体', 13)).place(x=10, y=20)
        # 收件人输入框
        self.to_text = Text(self.root, width=26, height=1.55, font=('黑体', 13))
        self.to_text.place(x=90, y=20)

        # 邮件主题标签
        title_label = Label(self.root, text='主题:', font=('黑体', 13)).place(x=10, y=80)
        # 邮件主题输入框
        self.title_text = Text(self.root, width=26, height=1.55, font=('黑体', 13))
        self.title_text.place(x=90, y=80)

        # 邮件内容提示标签
        contents_label = Label(self.root, text='内容:', font=('黑体', 13)).place(x=10, y=140)
        # 邮件内容输入框
        self.content_text = Text(self.root, width=75, height=12, font=('黑体', 13))
        self.content_text.place(x=90, y=140)

        #邮件附件按钮
        attachments_button = Button(self.root, text='附件地址', font=('黑体', 13), fg='white', bg='green', command=self.Attachments,width=10, height=2, relief=RAISED)
        attachments_button.place(x=30, y=370)
        #邮件附件提示标签
        self.attachments_label=Label(self.root, text='暂无选择文件', font=('黑体', 9),width=80, height=3, fg='white', bg='green')
        self.attachments_label.place(x=180, y=370)


        #邮件发送确认按钮
        check_button = Button(self.root, text='确认发送', font=('黑体', 13), fg='white', bg='green', command=self.Sendto, width=10,height=2, relief=RAISED).place(x=30, y=450)

        #程序状态标签
        tip_label = Label(self.root, text='程序状态:', font=('黑体', 13)).place(x=10, y=530)

        # 其文本内容对应着实际操作程序的操作提示的标签
        self.tipout_label = Label(self.root, text='暂无操作!', font=('黑体', 13), bg='green', fg='white')
        self.tipout_label.place(x=120, y=530)

        # 用于时间显示标签
        self.time_label = Label(self.root, text='', font=('黑体', 16), fg='green')
        self.time_label.place(x=340, y=85)

        self.menubar = Menu(self.root)  # 主菜单
        self.menuout = Menu(self.root, tearoff=0)  # 弹出菜单,清楚功能实现的汇集
        self.root['menu'] = self.menubar  # 设置主菜单
        # 菜单项加入:
        self.menubar.add_command(label="初始化配置文件  ", command=self.creatconfig)#初始化配置文件的菜单选项功能
        self.menubar.add_command(label="  打开配置文件  ", command=self.openconfig)#打开配置文件的菜单选项功能
        self.menubar.add_command(label="  草稿   ", command=self.textbook)
        self.menubar.add_command(label="  日历  ", command=self.show_datetime)
        self.root.bind("<Button-3>", self.pops)  # <Button-3>为右键点击事件,用于触发弹出菜单
        self.menuout.add_command(label='清空收件人窗口', command=self.Clear_to)
        self.menuout.add_command(label='清空主题窗口', command=self.Clear_title)
        self.menuout.add_command(label='清空内容窗口', command=self.Clear_content)
        self.menuout.add_command(label='清空附件地址', command=self.Clear_attachments)
        self.menuout.add_command(label='清空所有输入窗口', command=self.message)
        self.root.mainloop()

    # 附件控件控制函数
    def Attachments(self):
        self.filename = tkinter.filedialog.askopenfilename()  # 在弹出框内选择文件,并获得字符串型的文件地址
        if self.filename != '':  # 用filename是否为空字符串来判断,如果没选择的,就用初始量
            self.tipout_label['text'] = '您选择了附件文件!'
            self.attachments_label['text'] = '您选择的文件是' + self.filename
        else:
            self.tipout_label['text'] = '您没有选择任何文件!'
            self.attachments_label['text'] = '您还没选择任何文件!'

    # 主函数:处理邮件发送
    def Sendto(self):
        to = self.to_text.get('1.0', 'end')  # 获取相关内容
        title = self.title_text.get('1.0', 'end')
        content = self.content_text.get('1.0', 'end')
        if self.filename == '':  # 根据filename值来选择发送时是否包含附件
            try:  # 检查邮件发送是否成功很重要;
                self.mail.send(to, title, content)
                self.tipout_label['text'] = "发送成功!"
            except:
                self.message()
        elif self.filename != '':
            try:
                self.mail.send(to, title, content, self.filename)
                self.tipout_label['text'] = "发送成功!"
            except:
                self.message()

    def show_datetime(self):  # 利用calendar库显示日历的窗口
        winnew = Toplevel(self.root)  # 顶层窗体
        winnew.title('日历窗口')
        winnew.geometry('500x400+700+50')
        winnew.iconbitmap('mail.ico')  # 设置窗口图标,统一使用同一张
        self.tipout_label['text'] = '你点开了日历窗口!'  # 操作变化提示,基本每个模块被使用时都会含有
        date_time = datetime.datetime.today()
        year = date_time.year  # 获取当前年份
        month = date_time.month  # 获取当前月份
        calendar.setfirstweekday(firstweekday=6)  # 设置日历的初始天(第一天)
        dates = calendar.month(year, month)  # 获得日历的字符串类型
        alldate = Label(winnew, text='', bg='green', fg='white', width=1000, height=600, font=('黑体', 20),
                        image=self.background_image1, compound=CENTER)
        alldate.configure(text=dates)
        alldate.pack()

    def textbook(self):# 草稿操作的窗口
        text_win = Toplevel(self.root)
        text_win.title('草稿窗口')
        text_win.geometry('740x520+500+50')
        text_win.iconbitmap('mail.ico')
        self.tipout_label['text'] = '你点开了草稿窗口!'
        self.draft_paper = Text(text_win, width=100, height=30)  # 该实例为草稿箱输入和文本显示框功能
        self.draft_paper.insert('1.0', self.lists[0])  # 插入所保存的内容,相当记忆重现,实现了保存功能逻辑
        save_button = Button(text_win, text='保存', command=self.saves, relief=RAISED, fg='white', bg='green', font=('黑体', 14),
                             width=10, height=2).place(x=19, y=430)
        clear_button = Button(text_win, text='清空所有内容', command=self.clears, relief=RAISED, fg='white', bg='green',
                              font=('黑体', 14), width=16, height=2).place(x=150, y=430)
        self.draft_paper.place(x=19, y=18)

    def saves(self):#保存了草稿箱里的内容的方法
        self.lists[0] = self.draft_paper.get(1.0, 'end')  # 点击保存按钮,触发获取文本框的内容,可在编写过程任一时刻保存,避免丢失
        self.tipout_label['text'] = "你保存了草稿箱里的内容!"

    def clears(self):#清空草稿箱里的内容的方法
        self.draft_paper.delete('1.0', 'end')
        self.tipout_label['text'] = "你清空了草稿箱里的内容!"

    # 用于其他模块下错误信息提示的使用,使用时调用即可
    def message(self):
        self.tipout_label['text'] = "输入有误或已全清空!请重新输入所有内容!"
        self.to_text.delete('1.0', 'end')  # 文本框控件中第一个字符的位置是 1.0,可以用数字 1.0 或字符串"1.0"来表示
        self.title_text.delete('1.0', 'end')
        self.content_text.delete('1.0', 'end')
        self.filename=''
        self.tipout_label['text']='你清空了所有输入内容!包括收件人,主题,内容,附件地址的所有输入!'
        self.attachments_label['text']='您还没选择任何文件!'

    def pops(self,event):  # 右键响应函数,弹出菜单
        self.menuout.post(event.x_root, event.y_root)  # 这两个变量可让在在窗口任一触发部位弹出

    def Clear_to(self):  # 清空收件人输入框函数
        self.to_text.delete('1.0', 'end')
        self.tipout_label['text'] = '你清空了收件人窗口!'

    def Clear_title(self):  # 清空邮件主题输入框的方法
        self.title_text.delete('1.0', 'end')
        self.tipout_label['text'] = '你清空了主题窗口!'

    def Clear_content(self):  # 清空邮件内容输入框的方法
        self.content_text.delete('1.0', 'end')
        self.tipout_label['text'] = '你清空了内容窗口!'

    def Clear_attachments(self):
        self.filename=''
        self.tipout_label['text'] = '你清除了附件地址!'
        self.attachments_label['text'] = '您还没选择任何文件!'


if __name__ == '__main__':
    MAILGUI()

2.开发中遇到的问题

pyinstaller打包多个py文件和去除cmd黑框
报错:ModuleNotFoundError: No module named 'PIL’解决方法
python 获取当前年份和月份
Python中tkinter.filedialog
Python-Tkinter图形化界面设计(详细教程 )
用tkinter.pack设计复杂界面布局
python-基于yagmail库开发自动邮件发送程序

三,程序打包

1.打包过程

(1)找到自己代码文件的目录,复制下来
在这里插入图片描述
(2)打开cmd窗口,把复制的目录复制到cmd窗口,并在前加cd,如下例所示:
在这里插入图片描述
(3)确认已经下载安装好pyinstaller,输入如下指令:

pyinstaller -F <程序主文件>.py

在这里插入图片描述
(4)在生成的文件中,只保留<主程序>.spec文件,其余都删除(当然我们原来的py代码文件也在该目录下,肯定不用删除,保留就行)!如下:
在这里插入图片描述

(5)打开后缀为.spec文件,在Analysis中的第一行的列表,再添加我们主程序依赖和要导入的模块MAIL.py文件的字符串形式,如下图:
在这里插入图片描述

(6)再重新打开cmd,进入文件目录,输入以下指令:
该程序不用携带小黑框,所以要在命令后加上–noconsole语句

pyinstaller -F  <主程序名>.spec --noconsole

在这里插入图片描述
(7)提示打包成功后,我们可以删除生成的_pycache_和build文件,只保留dist文件夹,因为这里面放置了生成exe程序,另外程序窗体要用到mail.ico文件,默认打包是不会把它移到dist文件夹的,我们要复制到dist文件下!
在这里插入图片描述
(8)修改配置文件,如下:
在这里插入图片描述

2.程序功能展示及描述

程序各界面如下:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

控件功能描述注意事项
初始化配置文件顶层菜单选项初始化配置文件,相当恢复原厂设置,一般用于要修改配置
打开配置文件顶层菜单选项快速自动打开配置文件如果打开修改配置文件的话,保存配置文件后,需重新打开程序 ,方可正常运行
草稿顶层菜单选项打开草稿窗口
日历顶层菜单选项打开日历窗口
收件人输入框输入收件人的信息
邮件主题输入框输入邮件主题
邮件内容输入框输入邮件内容
邮件附件按钮选择邮件附件,若不点击,则默认无附件点击附件选择窗口后,若无选择文件,则默认无附件
邮件发送确认按钮输入所要要发送的信息,点击可发送根据系统运行环境和网络环境会,发送时会有不同程度的卡顿,但会正常运行下去的,不必奇怪
其他显示标签显示程序操作及相关提示等
草稿保存按钮保存草稿窗口所输入的内容保存范围在不关闭主程序窗口内,都有记忆功能
草稿清空按钮清空草稿内容
配置文件若删除,可在程序运行状态下,点击初始化配置文件按钮,即可生成

四,程序成品下载

为了更好地学习和分享该部分的内容,以及提供成品程序给大家直接观摩,特意放资源链接在此,供各位读者下载!
邮件发送GUI程序下载
如果大家有条件的话,可以到我的Github去看我的项目文件及代码,下面附上GitHub项目地址:
Python-tool-development-pip-instruction-GUI-program
最后,由于开发经验尚浅和程序其中的一些瑕疵,希望大家理解!
对于文中内容有任何问题,欢迎批评指正!!!

  • 7
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值