欢迎使用CSDN-markdown编辑器
2016-11-20 00:01
183 查看
软件课设:邮件管理系统
一 开发环境
操作系统 | 解释器 | 依赖模块 | 图形开发组件 |
---|---|---|---|
Windows | python>=3.4.4 | pyqt5 | QtDesigner |
脚本执行方法
在Src目录下,运行python3 pxmail.py.
可执行文件运行方法
直接运行Bin目录下已打包好的可执行文件(pxmail.exe)二 基本特点
采用python3编写,编码风格良好。结构清晰,代码耦合度低,可扩展性强,其中:正则引擎,GUI,邮件解析器等,皆为通用组件。
源代码注释详尽
实现效率高,核心模块方法都是线性级别。
跨平台,可在Linux、Windows、OSX运行
三 实现功能
基本功能
题目要求的基本功能全部实现:有较良好的图形界面
支持邮件的收发
支持邮件的转发、回复
支持邮件管理:浏览、查找、删除
支持QQ、sina、163、hust邮箱
支持html以及文本邮件的接收显示
拓展功能
支持多附件邮件接收和发送支持邮件发信人、主题、内容检索
按日期、发信人、主题邮件排序,支持升序、降序
邮件搜索采用正则表达引擎
实现了邮件内容语法高亮,提高用户体验
支持发送图片,截屏
通讯簿导入,导出,与Foxmail兼容
记住密码功能,并保存本地,用户名会加密
炫酷黑色皮肤,并可以切换皮肤
多线程接收邮件,基本可以达到秒收
四 项目架构
(一). 源码目录结构
Src ├── pxmail.py ├── parameter.py ├── mail.py ├── gui.py ├── backend.py ├── syntax_pars.py └── ui ├── accountdialog.ui ├── composewindow.ui ├── Contact.ui ├── mainwindow.ui ├── receivingDialog.ui ├── searchDialog.ui ├── sendDialog.ui └── ui.qss
简单说明:
pxmail.py入口主程序
gui.pyUI相关界面程序
parameter.py包含了一些定义的全局变量
mail.py邮件后端接收以及解析
backend.py实现登陆框字体渐变的方法
setup.py软件打包的脚本
ui/界面的实现ui素材文件
ui.qss黑色皮肤的样式文件
(二). 程序结构
gui.py
GUI主要接口,实现了登陆、浏览、发送等界面
class AccountDialog(QtWidgets.QMainWindow) #登陆界面 class MainWindow(QtWidgets.QMainWindow): #邮件浏览主界面 class Contact(QWidget): #联系人界面 class ComposeWindow(QtWidgets.QMainWindow) #发送邮件界面 class ReceiveDialog(QtWidgets.QDialog) #接收邮件对话框 class SendDialog(QtWidgets.QDialog) #发送邮件对话框
主界面MainWindow
重要接口: def OnActivated() #排序选项Combobox def mailDisplay() #邮件按排序显示目录 def save_binary_file() #附件保存为二进制文件 def openFile() #打开附件 def onComposeMail() #打开发送邮件界面 def onRefresh() #刷新邮件列表 def onContactList() #显示联系人列表 def InitSearchEdit() #初始化搜索框 def onReply() #回复邮件 def onForward() #转发邮件 def onDelete() #删除邮件 def onFolderSelected() #显示邮件夹目录 def onMailSelected() #显示邮件内容 def makeFolder() #新建邮件夹 def deleteFolder() #删除邮件夹 def folderMenu() #文件夹菜单 def changeBackground() #切换皮肤
登陆界面AccountDialog
重要接口: def hideManualSet() #隐藏手动设置 def showManualSet() #展开手动设置 def txtuserEdited() #文本编辑完成自动显示服务器文本 def ontextChanged() #文本框自动补全 def onLogin() #登陆邮箱 def save() #保存密码到本地 def trans() #改变透明度,淡入淡出
发送界面ComposeWindow
重要接口: def onAttachment() #添加附件 def ontextChanged() #文本框自动补全 def onSend() #发送邮件 def InitRichText() #初始化富文本编辑器 def addPerson() #添加联系人 def fileSave() #保存邮件到草稿箱 def insertImage() #插入图片 def onScreenCut() #截屏 def createAttachmentsMenuItems() #创建附件菜单
联系人界面Contact
重要接口: def exportCsv() #导出通讯录 def importCsv() #导入通讯录 def SetupCsv() #初始化通讯录 def PersonDisplay() #显示联系人列表 def onPeopleSelected() #显示联系人内容 def onEdit() #编辑联系人 def onCreatperson() #新建联系人 def onDeleteperson() #删除联系人 def onComposeMail() #发送邮件
mail.py
包含了邮件接收、发送线程,邮件解析器,邮件缓存机制
class loadingThread(QtCore.QThread) #登陆线程 class sendingThread(QtCore.QThread) #邮件发送线程 class receiveThread(QtCore.QThread) #邮件接收线程 class MyThread(Thread) #多线程并行接收邮件 class MailCache() #邮件缓存、记录时间戳 def CleanDir(Dir) #清除目录下文件 def guess_charset(msg) #获得字符编码方法 def decode_str(s) #字符编码转换方法 def get_info(msg, indent = 0) #邮件解码,获取内容 class Attachment(object) #自定义附件数据结构
邮件缓存MailCache
重要接口: def _is_stale(self, folder) #检测上一次时间戳 def _renew_state(self, folder) #刷新时间戳 def _load_state(self) #读取时间戳 def _commit_state(self) #写入时间戳
backend.py
界面美化,字体渐变
class Trans(QThread) #淡入淡出提示文字 class In(QThread): #淡入提示文字
(三). 核心函数说明
(1)登陆模块
1.1登陆服务器读取用户输入到文本框的用户名密码,调用poplib类并连接到服务器
def onLogin(self): gl.username=self.txtuser.text().strip() gl.password=self.txtpassword.text() if gl.popssl: pop_backend = poplib.POP3_SSL(gl.pophost,gl.popport) #SSL加密登陆 else: pop_backend = poplib.POP3(gl.pophost,gl.popport) pop_backend.user(gl.username) pop_backend.pass_(gl.password) resp, gl.mails_number, octets = pop_backend.list()
1.2记住密码机制
初始化登陆的时候从本地配置文件config.ini加载用户名密码,密码做了简单的加密操作,需将密文转换成明文
def Initlogin(): self.config=configparser.ConfigParser() self.config.read('config.ini') gl.smtpport = self.config.get('mail', 'smtpport') gl.popport = self.config.get('mail', 'popport') secret_user = self.config.get('mail', 'user') secret_passwd = self.config.get('mail', 'passwd') for i in range(0,len(secret_user)): gl.username += chr(ord(secret_user[i]) ^ 7) for i in range(0,len(secret_passwd)): gl.password += chr(ord(secret_passwd[i]) ^ 5)
1.3文本框自动补全
设置一个下拉框,读取用户输入的当前用户名,假如没出现@,就自动列出qq、sina等邮箱进行自动补全,方便用户使用
def ontextChanged(self): completer = QtWidgets.QCompleter() #文本框自动补全 self.txtuser.setCompleter(completer) self.model=QtCore.QStringListModel() completer.setModel(self.model) getstring=self.txtuser.text() if not "@" in getstring: self.model.setStringList([getstring+"@qq.com", getstring+"@sina.com",getstring+"@sina.cn", getstring+ "@163.com",getstring+"@126.com", getstring+"@hust.edu.cn"])
(2)发送邮件模块
2.1 发送邮件定义一个MIME对象,并填充该数据结构,数据为用户输入的收件人,正文,附件以及图片等等,然后利用smtplib库连接到SMTP服务器,使用用户名密码登陆该邮箱并将以上MIME邮件发送出去
def onSend(self): gl.message = MIMEMultipart('related') gl.message['Subject'] = self.txtsubject.text() gl.message['from'] = gl.username gl.message['date']=time.strftime('%a, %d %b %Y %H:%M:%S %z') gl.message.attach(MIMEText(self.textEdit.document().toHtml(), 'html', 'utf-8')) for filename in self.fileName: #构造附件 basename = os.path.basename(filename) msg_attach = MIMEBase('application', 'octet-stream', filename = basename) msg_attach.set_payload(open(filename, 'rb').read()) encoders.encode_base64(msg_attach) msg_attach.add_header('Content-Disposition', 'attachment', filename = basename) gl.message.attach(msg_attach) gl.receivers=self.txtreceiver.text().split(';') smtp_backend = smtplib.SMTP(gl.smtphost, 25) smtp_backend.login(gl.username,gl.password) smtp_backend.sendmail(gl.username, gl.receivers, gl.message.as_string())
2.2添加附件
弹出文件对话框,选择相应文件,创建一个按钮对象并显示到前端用于编辑操作
def onAttachment(self,ReplyFile=None): if ReplyFile: fileName=ReplyFile else: fileName, filetype = QFileDialog.getOpenFileName(self, "选取文件", "C:/", "All Files (*);;Text Files (*.txt)") #设置文件扩展名过滤,注意用双分号间隔 self.fileName.append(fileName) button = QtWidgets.QPushButton( None) button.setMenu(self.attachmentContextMenu) button.setToolTip(fileName) button.setText(os.path.basename(fileName)) button.attachment = None button.setMaximumSize(200,40) button.setFocusPolicy(Qt.NoFocus) self.layout.addWidget(button)
2.3截屏
调用Qt的API接口,保存当前屏幕到本地,并插入到邮件编辑框
def onScreenCut(self): format = 'png' screen = QApplication.primaryScreen() if screen is not None: self.originalPixmap = screen.grabWindow(0) else: self.originalPixmap = QtGui.QPixmap() self.originalPixmap.save('utitled.png', format) filename='utitled.png' image = QtGui.QImage(filename) cursor = self.textEdit.textCursor() cursor.insertImage(image,filename)
2.4富文本编辑器
+
此处涉及函数过多,只列出相应的方法
# 当前文字格式改变 def onCurrentCharFormatChanged(self, format) #光标位置改变 def onCursorPositionChanged(self) #字体改变 def fontChanged(self, font) #字体加粗 def onTextBold(self) #斜体显示 def onTextItalic(self) #下划线 def onTextUnderline(self) #字体颜色 def onTextColor(self) #文字字体 def onTextFamily(self,family) #文字大小 def onTextSize(self,pointSize) #文字对齐 def onTextAlign(self,button) #改变字体 def fontChanged(self, font) #改变颜色 def colorChanged(self, color) #改变对齐 def alignmentChanged(self, alignment) #剪贴板变换 def clipboardDataChanged(self) #选中词汇合并格式 def mergeFormatOnWordOrSelection(self, format)
(3)接收邮件模块
3.1 POP3接收邮件利用poplib库连接到POP3服务器,使用用户名密码登陆该邮箱并将指定邮件下载到本地,先利用chardet判断邮件文字编码方式进行解析,然后调用Parser库进行base64解码获取邮件内容
def run(self): ipop_backend = poplib.POP3(gl.pophost,gl.popport) ipop_backend.user(gl.username) ipop_backend.pass_(gl.password) MailIndex = len(gl.mails_number)-counter resp, lines, octets = ipop_backend.retr(MailIndex) msg_byte = b'\r\n'.join(lines) msg_content=msg_byte.decode(chardet.detect(msg_byte)['encoding']) msg = Parser().parsestr(msg_content) mails.append((len(gl.mails_number)-MailIndex+1,msg)) 多线程并行调用: for i in range(len(gl.mails_number)): my_thread = MyThread() my_thread.start() threads.append(my_thread) for thread in threads: #回收线程 thread.join()
3.2 搜索邮件
根据用户输入的关键词,利用python自带的in方法匹配字符串,并添加到显示列表
def txtsearchEdited(self): gl.string=self.searchEdit.text().replace(' ','').split('|')[0] gl.March_ID=[] #匹配符合条件的邮件 for email in gl.emails: info=get_info(email["message"]) if (gl.string in info["subject"]) or (gl.string in info["content"]) or (gl.string in info["addr"]): gl.March_ID.append(email) self.data=info["subject"]+info["content"]+info["addr"] #匹配得到关键字高亮显示 info["content"]="<strong><font color='#ffffff'>"+info["content"]+"</font></strong>"
3.3 切换皮肤
通过加载相应的界面样式文件来实现当前皮肤颜色的变化,样式文件通过qss语言实现
def changeBackground(self): if self.background: with open("ui/white.qss","r") as fh: #加载qss文件 self.setStyleSheet(fh.read()) self.background=False else : with open("ui/ui.qss","r") as fh: #加载qss文件 self.setStyleSheet(fh.read()) self.background=True
(四)通讯录模块
4.1 导入通讯录+
打开相应的csv文件,提取通讯录数据,保存到本地并显示到前端
def importCsv(self): filePath,filetype = QFileDialog.getOpenFileName(self,"导入通讯录", '.', "CSV (*.csv)",) if filePath: self.contact_table=[] with open(filePath, 'r') as csvfile: csv_reader = csv.DictReader(csvfile) for row in csv_reader: self.contact_table.append(row) self.WriteCsv() self.SetupCsv() self.PersonDisplay()
4.2导出通讯录
+
导出本地通讯录数据,为了与foxmail兼容,我们将数据保存为csv文件格式,这样可以使foxmail正确读取到
def exportCsv(self): filename, filetype = QFileDialog.getSaveFileName(self,"导出通讯录", '.',"CSV (*.csv)" ) if not filename: return qFile = QtCore.QFile(filename) if not qFile.open(QtCore.QFile.WriteOnly | QtCore.QFile.ReadWrite): QtWidgets.QMessageBox.warning(self, APPNAME, "无法创建文件: %s\n%s." % (filename, qFile.errorString())) return with open(filename,"w",newline="") as datacsv: csvwriter = csv.writer(datacsv,dialect = ("excel")) #csv文件插入一行数据,把下面列表中的每一项放入一个单元格(可以用循环插入多行) csvwriter.writerow(["姓名","电子邮件地址","性别","生日","手机","QQ", "家庭住址","公司","部门","职位","公司地址"]) for person in self.contact_table: csvwriter.writerow([person["姓名"],person["电子邮件地址"],person["性别"],person["生日"],person["手机"],person["QQ"],person["家庭住址"],person["公司"],person["部门"],person["职位"],person["公司地址"]])
4.3 新建联系人
+
定义一个person数据结构,并添加到contact_table联系人列表里面
def onCreatperson(self): person={"姓名":'未命名', "电子邮件地址":'', "性别":'', "生日":'', "手机":'', "QQ":'', "家庭住址":'', "公司":'', "部门":'', "职位":'', "公司地址":''} self.contact_table.append(person) self.PersonDisplay()
4.4 删除联系人
+
将contact_table联系人列表里面删除相应的成员,然后刷新前端显示列表,并将此时的数据成员写到本地配置文件里
def onDeleteperson(self): self.contact_table.pop(self.index) self.PersonDisplay() self.widgetShow.hide() self.widgetEdit.hide() self.WriteCsv()
(五)界面美化
主要在ui/ui.qss文件里面,用qss标记语言实现,文件较庞大,这里只展示部分
QWidget #主界面黑色效果 { color: #eff0f1; background-color: #31363b; selection-background-color:#3daee9; selection-color: #eff0f1; background-clip: border; border-image: none; border: 0px transparent black; outline: 0; } QComboBox:hover,QPushButton:hoverQLineEdit:hover,QTextEdit:hover,QTreeView:hover #文本框划过会有蓝色边框效果 { border: 1px solid #3daee9; color: #eff0f1; }
五 程序逻辑
接收流程
Created with Raphaël 2.1.0登陆邮箱刚收过邮件?显示在前端POP3协议收取邮件yesno先从登陆界面进入主界面
调用
onFolderSelected(self, folder)选择当前显示目录
启动
receiveThread()接收线程
调用
MailCache()创建当前用户的缓存邮件夹,记下当前时间戳
若当前时间遇上一次时间戳在一个周期内,则直接显示在前端,否则就先采用POP3协议从邮件服务器收取邮件到本地
调用
mailDisplay(self)输出结果
六 更新日志
2016/10/7 本次更新:1.实现基本的SMTP和POP3协议收发邮件
2.实现了UI界面的整体框架
2016/10/23 本次更新:
1.解决了收取邮件时画面卡顿的问题
2.支持qq、sina、163、126、hust邮箱
3.增加了登陆失败提示
4.增加了回车快捷键
2016/11/3 本次更新:
1.增加了显示收信人、日期、主题
2.增加了回复、转发功能
3.增加了搜索功能
4.初步尝试对界面做了小幅改动,之后还会修改
2016/11/10 本次更新:
1.对邮件协议里的日期做了格式化处理
2.增加了对邮件按日期、收信人、主题排序
3.支持带附件邮件的接收,保存到本地,暂未想好如何显示到前端
4.搜索支持关键词背景高亮
5.实现了邮件内容语法高亮,提高用户体验
2016/11/12 本次更新:
1.增加了附件显示,能以系统默认程序打开和另存为
2016/12/4 本次更新:
1.支持多用户接受邮件,收件人以分号分隔
2.美化了登陆界面,增加了文字淡入淡出效果,提高了用户体验
3.修复了部分HTML邮件显示异常的BUG
4.添加了富文本编辑器
5.写邮件时可以保存邮件至草稿箱
6.支持html邮件发送
7.修复了QQ邮箱不能发送邮件的问题
2016/12/16 本次更新:
1.完成了联系人模块
2.支持联系人导入导出csv文件,并与foxmail兼容
2016/12/17 本次更新:
1.修复了删除联系人会导致界面崩溃的BUG
2016/12/20 本次更新:
1.增加了记住密码机制
2.解决了频繁刷新界面会崩溃的BUG
3.解决了发送附件文件格式的问题
4.支持发送图片
5.支持接收图片
6.可以在发邮件里面添加联系人
7.发送邮件的对话框美化,加了进度条
8.可以删除邮件,并从服务器上也一并删除
2016/12/28 本次更新:
1.多线程并行接收邮件,基本可以达到秒收
2.可以发送多个邮件,并可以编辑管理,删除
3.实现了多个附件的接收
4.回复和转发也支持转发附件了..
2016/12/31 本次更新:
1.字体黑转白,由于部分html邮件是黑色字体,增加了可以切换皮肤的功能
2.支持邮件夹管理,添加,删除
七 运行截图
相关文章推荐
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器ss
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器