您的位置:首页 > 其它

欢迎使用CSDN-markdown编辑器

2016-11-20 00:01 183 查看

软件课设:邮件管理系统

一 开发环境

操作系统解释器依赖模块图形开发组件
Windowspython>=3.4.4pyqt5QtDesigner
为获得最佳用户体验,请使用Windows8,python3.4.4 运行并测试

脚本执行方法

在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.py
UI相关界面程序

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.支持邮件夹管理,添加,删除

七 运行截图









内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: