python: wxpython 4.2 开发一个邮件客户端,能编写邮件,发送邮件及附件
以下是一个使用 wxPython 4.2 开发的简单邮件客户端程序,支持编写邮件、添加附件和发送邮件功能:
编写 eMailClient_wx.py 如下
import os
import wx
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encodersclass EmailClient(wx.Frame):def __init__(self):super().__init__(None, title="邮件客户端", size=(1000, 600))# 初始化附件列表self.attachments = []# 创建主面板panel = wx.Panel(self)vbox = wx.BoxSizer(wx.VERTICAL)# 服务器设置server_box = wx.StaticBox(panel, label="SMTP服务器设置")server_sizer = wx.StaticBoxSizer(server_box, wx.VERTICAL)server_grid = wx.FlexGridSizer(cols=2, vgap=10, hgap=10)server_grid.Add(wx.StaticText(panel, label="SMTP服务器:"), 0, wx.ALIGN_CENTER_VERTICAL)self.smtp_server = wx.TextCtrl(panel, value="smtp.qq.com")server_grid.Add(self.smtp_server, 1, wx.EXPAND)server_grid.Add(wx.StaticText(panel, label="端口:"), 0, wx.ALIGN_CENTER_VERTICAL)self.port = wx.TextCtrl(panel, value="465")server_grid.Add(self.port, 1, wx.EXPAND)server_grid.Add(wx.StaticText(panel, label="邮箱账号:"), 0, wx.ALIGN_CENTER_VERTICAL)self.email = wx.TextCtrl(panel)server_grid.Add(self.email, 1, wx.EXPAND)server_grid.Add(wx.StaticText(panel, label="密码:"), 0, wx.ALIGN_CENTER_VERTICAL)self.password = wx.TextCtrl(panel, style=wx.TE_PASSWORD)server_grid.Add(self.password, 1, wx.EXPAND)server_sizer.Add(server_grid, 1, wx.EXPAND|wx.ALL, 10)# 邮件内容mail_box = wx.StaticBox(panel, label="邮件内容")mail_sizer = wx.StaticBoxSizer(mail_box, wx.VERTICAL)mail_grid = wx.FlexGridSizer(cols=2, vgap=10, hgap=10)mail_grid.AddGrowableCol(1, 1)mail_grid.Add(wx.StaticText(panel, label="收件人:"), 0, wx.ALIGN_CENTER_VERTICAL)self.to_email = wx.TextCtrl(panel)mail_grid.Add(self.to_email, 1, wx.EXPAND)mail_grid.Add(wx.StaticText(panel, label="主题:"), 0, wx.ALIGN_CENTER_VERTICAL)self.subject = wx.TextCtrl(panel)mail_grid.Add(self.subject, 1, wx.EXPAND)mail_grid.Add(wx.StaticText(panel, label="附件:"), 0, wx.ALIGN_CENTER_VERTICAL)attachment_sizer = wx.BoxSizer(wx.HORIZONTAL)self.attachment_list = wx.ListBox(panel, size=(-1, 60))attachment_sizer.Add(self.attachment_list, 1, wx.EXPAND)btn_add = wx.Button(panel, label="添加附件")btn_add.Bind(wx.EVT_BUTTON, self.on_add_attachment)attachment_sizer.Add(btn_add, 0, wx.LEFT, 5)btn_remove = wx.Button(panel, label="移除")btn_remove.Bind(wx.EVT_BUTTON, self.on_remove_attachment)attachment_sizer.Add(btn_remove, 0, wx.LEFT, 5)mail_grid.Add(attachment_sizer, 1, wx.EXPAND)mail_grid.Add(wx.StaticText(panel, label="正文:"), 0, wx.ALIGN_TOP)self.body = wx.TextCtrl(panel, style=wx.TE_MULTILINE, size=(-1, 200))mail_grid.Add(self.body, 1, wx.EXPAND)mail_sizer.Add(mail_grid, 1, wx.EXPAND|wx.ALL, 10)# 发送按钮send_btn = wx.Button(panel, label="发送邮件")send_btn.Bind(wx.EVT_BUTTON, self.on_send)# 添加所有组件到主布局vbox.Add(server_sizer, 0, wx.EXPAND|wx.ALL, 10)vbox.Add(mail_sizer, 1, wx.EXPAND|wx.ALL, 10)vbox.Add(send_btn, 0, wx.ALIGN_CENTER|wx.ALL, 10)panel.SetSizer(vbox)# 状态栏self.CreateStatusBar()self.SetStatusText("准备就绪")self.Show(True)def on_add_attachment(self, event):"""添加附件"""with wx.FileDialog(self, "选择附件", wildcard="所有文件 (*.*)|*.*", style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.FD_MULTIPLE) as dialog:if dialog.ShowModal() == wx.ID_CANCEL:returnpaths = dialog.GetPaths()for path in paths:if path not in self.attachments:self.attachments.append(path)self.attachment_list.Append(os.path.basename(path))def on_remove_attachment(self, event):"""移除选中的附件"""selection = self.attachment_list.GetSelection()if selection != wx.NOT_FOUND:self.attachments.pop(selection)self.attachment_list.Delete(selection)def on_send(self, event):"""发送邮件"""# 获取输入值smtp_server = self.smtp_server.GetValue()port = self.port.GetValue()email = self.email.GetValue()password = self.password.GetValue()to_email = self.to_email.GetValue()subject = self.subject.GetValue()body = self.body.GetValue()# 验证输入if not all([smtp_server, port, email, password, to_email]):wx.MessageBox("请填写所有必填字段", "错误", wx.OK | wx.ICON_ERROR)returntry:# 创建邮件msg = MIMEMultipart()msg['From'] = emailmsg['To'] = to_emailmsg['Subject'] = subject# 添加正文msg.attach(MIMEText(body, 'plain'))# 添加附件for file_path in self.attachments: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={os.path.basename(file_path)}')msg.attach(part)# 连接SMTP服务器并发送self.SetStatusText("正在连接服务器...")with smtplib.SMTP(smtp_server, int(port)) as server:server.starttls()self.SetStatusText("登录中...")server.login(email, password)self.SetStatusText("发送邮件中...")server.sendmail(email, to_email.split(','), msg.as_string())# 清空表单self.attachments = []self.attachment_list.Clear()self.to_email.Clear()self.subject.Clear()self.body.Clear()self.SetStatusText("邮件发送成功!")wx.MessageBox("邮件已成功发送", "成功", wx.OK | wx.ICON_INFORMATION)except Exception as e:self.SetStatusText(f"发送失败: {str(e)}")wx.MessageBox(f"发送邮件时出错:\n{str(e)}", "错误", wx.OK | wx.ICON_ERROR)if __name__ == "__main__":app = wx.App()EmailClient()app.MainLoop()
使用说明:
-
SMTP服务器设置:
- 输入您的SMTP服务器地址(如:smtp.gmail.com)
- 端口号(如:587 用于TLS)
- 邮箱账号和密码
-
邮件内容:
- 填写收件人邮箱(多个邮箱用逗号分隔)
- 邮件主题
- 使用"添加附件"按钮添加文件
- 在正文区域编写邮件内容
-
发送邮件:
- 点击"发送邮件"按钮发送
注意事项:
- 此程序需要使用支持SMTP的邮箱服务,并确保已开启SMTP服务
- 对于Gmail等邮箱,可能需要启用"安全性较低的应用的访问权限"
- 附件大小受邮箱服务商限制
- 密码以明文形式存储,请谨慎使用
依赖库安装:
pip install wxPython==4.2.0
此程序实现了基本的邮件发送功能,包括:
- SMTP服务器配置
- 邮件内容编辑
- 多附件支持
- 邮件发送状态反馈
- 基本的错误处理
您可以根据需要进一步扩展功能,如添加HTML格式支持、收件箱查看功能、邮件保存草稿等。
优化调整布局
下面是根据您的要求调整布局后的邮件客户端程序,将SMTP服务器和端口放在一行,邮箱账号和密码放在一行:
编写 eMailClient_wx4.py 如下
import os
import wx
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encodersclass EmailClient(wx.Frame):def __init__(self):super().__init__(None, title="邮件客户端", size=(1000, 600))# 初始化附件列表self.attachments = []# 创建主面板panel = wx.Panel(self)vbox = wx.BoxSizer(wx.VERTICAL)# 服务器设置server_box = wx.StaticBox(panel, label="SMTP服务器设置")server_sizer = wx.StaticBoxSizer(server_box, wx.VERTICAL)# 第一行:SMTP服务器和端口server_row1 = wx.BoxSizer(wx.HORIZONTAL)server_row1.Add(wx.StaticText(panel, label="SMTP服务器:"), 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5)self.smtp_server = wx.TextCtrl(panel, value="smtp.qq.com")server_row1.Add(self.smtp_server, 1, wx.EXPAND|wx.RIGHT, 10)server_row1.Add(wx.StaticText(panel, label="端口:"), 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5)self.port = wx.TextCtrl(panel, value="465", size=(60, -1))server_row1.Add(self.port, 0, wx.EXPAND)# 第二行:邮箱账号和密码server_row2 = wx.BoxSizer(wx.HORIZONTAL)server_row2.Add(wx.StaticText(panel, label="邮箱账号:"), 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5)self.email = wx.TextCtrl(panel)server_row2.Add(self.email, 1, wx.EXPAND|wx.RIGHT, 10)server_row2.Add(wx.StaticText(panel, label="密码:"), 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5)self.password = wx.TextCtrl(panel, style=wx.TE_PASSWORD)server_row2.Add(self.password, 1, wx.EXPAND)# 将两行添加到服务器sizerserver_sizer.Add(server_row1, 0, wx.EXPAND|wx.ALL, 10)server_sizer.Add(server_row2, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.BOTTOM, 10)# 邮件内容mail_box = wx.StaticBox(panel, label="邮件内容")mail_sizer = wx.StaticBoxSizer(mail_box, wx.VERTICAL)mail_grid = wx.FlexGridSizer(cols=2, vgap=10, hgap=10)mail_grid.AddGrowableCol(1, 1)mail_grid.Add(wx.StaticText(panel, label="收件人:"), 0, wx.ALIGN_CENTER_VERTICAL)self.to_email = wx.TextCtrl(panel)mail_grid.Add(self.to_email, 1, wx.EXPAND)mail_grid.Add(wx.StaticText(panel, label="主题:"), 0, wx.ALIGN_CENTER_VERTICAL)self.subject = wx.TextCtrl(panel)mail_grid.Add(self.subject, 1, wx.EXPAND)mail_grid.Add(wx.StaticText(panel, label="附件:"), 0, wx.ALIGN_CENTER_VERTICAL)attachment_sizer = wx.BoxSizer(wx.HORIZONTAL)self.attachment_list = wx.ListBox(panel, size=(-1, 60))attachment_sizer.Add(self.attachment_list, 1, wx.EXPAND)btn_add = wx.Button(panel, label="添加附件")btn_add.Bind(wx.EVT_BUTTON, self.on_add_attachment)attachment_sizer.Add(btn_add, 0, wx.LEFT, 5)btn_remove = wx.Button(panel, label="移除")btn_remove.Bind(wx.EVT_BUTTON, self.on_remove_attachment)attachment_sizer.Add(btn_remove, 0, wx.LEFT, 5)mail_grid.Add(attachment_sizer, 1, wx.EXPAND)mail_grid.Add(wx.StaticText(panel, label="正文:"), 0, wx.ALIGN_TOP)self.body = wx.TextCtrl(panel, style=wx.TE_MULTILINE, size=(-1, 200))mail_grid.Add(self.body, 1, wx.EXPAND)mail_sizer.Add(mail_grid, 1, wx.EXPAND|wx.ALL, 10)# 发送按钮send_btn = wx.Button(panel, label="发送邮件")send_btn.Bind(wx.EVT_BUTTON, self.on_send)# 添加所有组件到主布局vbox.Add(server_sizer, 0, wx.EXPAND|wx.ALL, 10)vbox.Add(mail_sizer, 1, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.BOTTOM, 10)vbox.Add(send_btn, 0, wx.ALIGN_CENTER|wx.ALL, 10)panel.SetSizer(vbox)# 状态栏self.CreateStatusBar()self.SetStatusText("准备就绪")self.Show(True)def on_add_attachment(self, event):"""添加附件"""with wx.FileDialog(self, "选择附件", wildcard="所有文件 (*.*)|*.*", style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.FD_MULTIPLE) as dialog:if dialog.ShowModal() == wx.ID_CANCEL:returnpaths = dialog.GetPaths()for path in paths:if path not in self.attachments:self.attachments.append(path)self.attachment_list.Append(os.path.basename(path))def on_remove_attachment(self, event):"""移除选中的附件"""selection = self.attachment_list.GetSelection()if selection != wx.NOT_FOUND:self.attachments.pop(selection)self.attachment_list.Delete(selection)def on_send(self, event):"""发送邮件"""# 获取输入值smtp_server = self.smtp_server.GetValue()port = self.port.GetValue()email = self.email.GetValue()password = self.password.GetValue()to_email = self.to_email.GetValue()subject = self.subject.GetValue()body = self.body.GetValue()# 验证输入if not all([smtp_server, port, email, password, to_email]):wx.MessageBox("请填写所有必填字段", "错误", wx.OK | wx.ICON_ERROR)returntry:# 创建邮件msg = MIMEMultipart()msg['From'] = emailmsg['To'] = to_emailmsg['Subject'] = subject# 添加正文msg.attach(MIMEText(body, 'plain'))# 添加附件for file_path in self.attachments: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={os.path.basename(file_path)}')msg.attach(part)# 连接SMTP服务器并发送self.SetStatusText("正在连接服务器...")# 根据端口选择连接方式if port == "465":# 使用SSL加密server = smtplib.SMTP_SSL(smtp_server, int(port))else:# 普通连接,可能使用STARTTLSserver = smtplib.SMTP(smtp_server, int(port))if port == "587":server.starttls()self.SetStatusText("登录中...")server.login(email, password)self.SetStatusText("发送邮件中...")server.sendmail(email, to_email.split(','), msg.as_string())server.quit()# 清空表单self.attachments = []self.attachment_list.Clear()self.to_email.Clear()self.subject.Clear()self.body.Clear()self.SetStatusText("邮件发送成功!")wx.MessageBox("邮件已成功发送", "成功", wx.OK | wx.ICON_INFORMATION)except Exception as e:self.SetStatusText(f"发送失败: {str(e)}")wx.MessageBox(f"发送邮件时出错:\n{str(e)}", "错误", wx.OK | wx.ICON_ERROR)if __name__ == "__main__":app = wx.App()EmailClient()app.MainLoop()
主要改进:
-
布局调整:
- SMTP服务器和端口放在同一行
- 邮箱账号和密码放在同一行
- 使用水平布局器(wx.BoxSizer)替代原来的网格布局器(wx.FlexGridSizer)
- 优化了控件间的间距和对齐方式
-
SMTP连接改进:
- 根据端口自动选择连接方式
- 465端口使用SSL加密连接
- 587端口使用STARTTLS
- 其他端口使用普通连接
-
界面优化:
- 端口输入框宽度调整为60像素
- 控件间添加了适当的间距
- 输入框使用比例分配空间
- 状态栏显示更详细的发送过程信息
使用说明:
-
SMTP服务器设置:
- 第一行:SMTP服务器地址和端口
- 第二行:邮箱账号和密码
- 端口默认设置为465(SSL加密)
-
邮件内容:
- 收件人:可输入多个邮箱,用逗号分隔
- 主题:邮件标题
- 附件:可添加多个附件
- 正文:邮件内容编辑区
-
发送邮件:
- 点击"发送邮件"按钮
- 发送过程会在状态栏显示进度
- 发送成功后会清空邮件内容
注意事项:
- 对于Gmail等邮箱,可能需要开启"低安全性应用访问"
- 465端口通常使用SSL加密,587端口使用STARTTLS
- 附件大小受邮箱服务商限制
- 密码以明文形式存储,请谨慎使用
这个版本的布局更加紧凑合理,SMTP服务器设置部分按照您的要求进行了调整,同时保持了原有的功能完整性。