• wxpython制作eml文件阅读器


          处理eml文件,一般windows下会启用默认的outlook来阅读,实际上python的email模块可以很简单的实现对eml文件的阅读,闲来木事,利用wxpython制作了一个eml文件阅读器,实现了对eml文件正文的阅读和附件的阅读,但由于制作时,在信头读取部分使用了label,在格式处理时未处理好,当信件有多个收件人时,会出现格式混乱。另外,附件如果有多个,只会显示最后一个。哪位感兴趣或者有时间可以自己改一下。
        一、email模块对eml文件的读取
        首先先来看一个邮件的源文件:
    Received: from 192.168.208.56 ( 192.168.208.56 [192.168.208.56] ) by
    ajax-webmail-wmsvr37 (Coremail) ; Thu, 12 Apr 2007 12:07:48 +0800 (CST)
    Date: Thu, 12 Apr 2007 12:07:48 +0800 (CST)
    From: user1 <xxxxxxxx@163.com>
    To: user2 <YYYY@163.com>
    Message-ID: <31571419.200911176350868321.JavaMail.root@bj163app37.163.com>
    Subject: =?gbk?B?u+nJtA==?=
    MIME-Version: 1.0
    Content-Type: multipart/Alternative;
    boundary="----=_Part_21696_28113972.1176350868319"

    ------=_Part_21696_28113972.1176350868319
    Content-Type: text/plain; charset=gbk
    Content-Transfer-Encoding: base64

    ztLS0b+qyrzS1M6qysfSu7j20MfG2ru70ru0zqOs1K3AtMrH0ru49tTCtffSu7TOztLDx8/W1NrT
    prjDysew67XjssXE3MjI1ebC6bezICAg
    ------=_Part_21696_28113972.1176350868319
    Content-Type: text/html; charset=gbk
    Content-Transfer-Encoding: quoted-printable

    <DIV>=CE=D2=D2=D1=BF=AA=CA=BC=D2=D4=CE=AA=CA=C7=D2=BB=B8=F6=D0=C7=C6=DA=BB=
    =BB=D2=BB=B4=CE=A3=AC=D4=AD=C0=B4=CA=C7=D2=BB=B8=F6=D4=C2=B5=F7=D2=BB=B4=CE=
    </DIV>
    <DIV>=CE=D2=C3=C7=CF=D6=D4=DA=D3=A6=B8=C3=CA=C7=B0=EB=B5=E3=B2=C5=C4=DC=C8=
    =C8</DIV>
    <DIV>=D5=E6=C2=E9=B7=B3</DIV>
    ------=_Part_21696_28113972.1176350868319--
        从第一行到第一个空行之间的为信件头,后面的是信件体。通过outlook解码后,正文显示为:
    我已开始以为是一个星期换一次,原来是一个月调一次
    我们现在应该是半点才能热
    真麻烦

        下面,具体来看看email模块的使用。
    (1)打开eml文件,利用open语句,具体与打开其它文件一样,如fileopen=open('AAA.eml','r')。
    (2)email.message_from_file()创建message对象,此时会对fileopen内容进行初步解码。如msg = email.message_from_file(fileopen)
    (3)获取信件主题subject = msg.get("subject"),此时主题中含有 =?gbk?B?u+nJtA==?=这样的编码,以下代码用来解码

    h = email.Header.Header(subject)
    dh = email.Header.decode_header(h)
    subject = dh[0][0]
    

    解码后,正常显示为“婚纱”

    (4)解析发件人和收件人,发件人往往只有一个,所以可以直接用efrom=email.utils.parseaddr(msg.get("from"))[1]进行解析,收件人有时会有多个,可得用以下代码:

    for tolines in msg.get("to").splitlines():
    findst=tolines.find('<') #从to中找<位置
    if findst==-1:#判断是否只有一个收件人,当tolines中不含有'<'时,只存在一个收件人
        eto=email.utils.parseaddr(msg.get("to"))[1]
    else:
        eto=eto+tolines[findst:]+'\n' 
    

    (5)解析时间,etime=msg.get("date"),显示时间格式为Thu, 12 Apr 2007 12:07:48 +0800 (CST),这里可以再根据需要转换为2007年4月12日星期四 12:07。

    (6)解析正文和附件,代码如下:

    for bodycheck in msg.walk():
    if not bodycheck.is_multipart():
    psname = bodycheck.get_param("name")

    if psname:
    psh = email.Header.Header(psname)
    psdh = email.Header.decode_header(psh)
    psfname = psdh[0][0]

    data = bodycheck.get_payload(decode=True)

    try:
    f = open(psfname, 'wb')
    except:
    #
    f = open('tempps', 'wb')

    f.write(data)
    f.close()
    else:
    data=bodycheck.get_payload(decode=True)
    p=str(data)



      


    这里,邮件正文保存为p,str类型,附件文件名为psfname,并将附件保存在当前文件+下面。如果有多个附件都会保存在这里。
    (7)关闭文件fp.close()


        二、wxpython制作GUI
    (1)self.staticText1、self.textCtrl1、self.button1三个控件完成对eml文件的选取。点击self.button1后,利用wxfiledialog调取文件选择框,限定wildcard = "note source (*.eml)|*.eml",由于路径有时会出现中文错误,所以使用了encode('utf-8')进行编码。

    def OnButton1Button(self, event): #浏览
          dialog = wx.FileDialog(None, "Choose a file", os.getcwd(),"", wildcard, wx.OPEN)
          if dialog.ShowModal() == wx.ID_OK:
               aa=dialog.GetPath().encode('utf-8')
               self.textCtrl1.SetValue(aa.decode('utf-8'))
               self.reademail()
          dialog.Destroy()
          event.Skip()
    

      


    (2)利用self.htmlWindow1显示邮件正文。邮件正文读取后一般都是html代码,通过htmlWindow1进行正常显示。
    (3)实现邮件的另存为txt。邮件另存为txt时,遇到的主要问题是如何将html代码转换为带格式的txt文档,于是利用了正则和字符串的替换,替换为\n换行,然后又去掉了多余的换行,具体代码如下:

    def savetotxt(self,filena):#邮件另存为txt文件
    resultfile=''
    read=file('temps').read()
    readf_con=read.replace('&nbsp;','\n')
    readf_con=readf_con.replace('&#187;','\n')
    readf_con=re.sub("<!--.+?-->",'\n',readf_con)
    readf_con=re.sub("<.*?>",'\n',readf_con)
    readf_con=re.sub('\n+','\n',readf_con)
    for tt in readf_con.splitlines():
    tt=tt.rstrip()+'\n'
    resultfile=resultfile+tt #去除temps文件中多余的空行

    w=open(filena,'w')

    w.write(resultfile)
    w.close()



    目前该代码存在的主要问题是:
    1、收件人很多时,窗口格式会发生错乱
    2、附件有多个时,只能显示一个
    3、eml另存为时,附件只能保存最后一个
    有兴趣的朋友可以自行修改一下。

    完整代码如下:

    #-*- encoding: gb2312 -*-
    '''
    eml阅读器 V1.0
    小五义:http://www.cnblogs.com/xiaowuyi
    仍然存在问题:
    1、收件人很多时,窗口格式会发生错乱
    2、附件有多个时,只能显示一个
    3、eml另存为时,附件只能保存一个
    '''


    import wx
    import wx.html
    import os
    import email
    import re
    import shutil

    wildcard = "note source (*.eml)|*.eml"
    psfname='' #附件名

    def create(parent):
    return Frame1(parent)

    [wxID_FRAME1, wxID_FRAME1BUTTON1, wxID_FRAME1PANEL1, wxID_FRAME1STATICTEXT1, wxID_FRAME1STATICLINE1,
    wxID_FRAME1STATICTEXT2, wxID_FRAME1STATICTEXT3,wxID_FRAME1TEXTCTRL1, wxID_FRAME1HTMLWINDOW1,wxID_FRAME1BUTTON2
    ] = [wx.NewId() for _init_ctrls in range(10)]

    class Frame1(wx.Frame):
    def _init_ctrls(self, prnt):

    wx.Frame.__init__(self, id=wxID_FRAME1, name='', parent=prnt,
    pos=wx.Point(269, 142), size=wx.Size(899, 599),
    style=wx.DEFAULT_FRAME_STYLE, title='Eml文件阅读器 V1.0')
    self.SetClientSize(wx.Size(891, 565))
    self.Enable(True)
    self.SetIcon(wx.Icon(u'mb_4.ico', wx.BITMAP_TYPE_ICO)) #当前目录下放一个名为mb_4.ico的文件做图标

    self.panel1 = wx.Panel(id=wxID_FRAME1PANEL1, name='panel1', parent=self,
    pos=wx.Point(0, 0), size=wx.Size(891, 565),
    style=wx.TAB_TRAVERSAL)

    self.textCtrl1 = wx.TextCtrl(id=wxID_FRAME1TEXTCTRL1, name='textCtrl1',
    parent=self.panel1, pos=wx.Point(120, 16), size=wx.Size(632, 23),
    style=0, value=u'')
    self.textCtrl1.SetEditable(False)


    self.button1 = wx.Button(id=wxID_FRAME1BUTTON1, label=u'浏览',
    name='button1', parent=self.panel1, pos=wx.Point(776, 16),
    size=wx.Size(75, 23), style=0)
    self.button1.SetFont(wx.Font(11, wx.SWISS, wx.NORMAL, wx.BOLD, False,
    u'Tahoma'))
    self.button1.Bind(wx.EVT_BUTTON, self.OnButton1Button,
    id=wxID_FRAME1BUTTON1)

    self.staticText1 = wx.StaticText(id=wxID_FRAME1STATICTEXT1,
    label=u'文件名:', name='staticText1', parent=self.panel1,
    pos=wx.Point(45, 16), size=wx.Size(56, 23), style=0)
    self.staticText1.SetFont(wx.Font(11, wx.SWISS, wx.NORMAL, wx.BOLD, False,
    u'Tahoma'))

    self.htmlWindow1 = wx.html.HtmlWindow(id=wxID_FRAME1HTMLWINDOW1,
    name='htmlWindow1', parent=self.panel1, pos=wx.Point(72, 186),
    size=wx.Size(747, 300), style=wx.html.HW_SCROLLBAR_AUTO|wx.DOUBLE_BORDER)

    self.staticText2 = wx.StaticText(id=wxID_FRAME1STATICTEXT2,
    label=u' 发件人:\n 日 期:\n 收件人:\n 主 题:\n', name='staticText2', parent=self.panel1,
    pos=wx.Point(72, 80), size=wx.Size(747, 90), style=wx.html.HW_SCROLLBAR_AUTO)
    self.staticText2.SetFont(wx.Font(11, wx.SWISS, wx.NORMAL, wx.BOLD, False,
    u'Tahoma'))

    self.staticText3 = wx.StaticText(id=wxID_FRAME1STATICTEXT3,
    label=u' 附 件:', name='staticText3', parent=self.panel1,
    pos=wx.Point(72, 496), size=wx.Size(680, 14), style=0)
    self.staticText3.SetFont(wx.Font(11, wx.SWISS, wx.NORMAL, wx.BOLD, False,
    u'Tahoma'))

    self.staticLine1 = wx.StaticLine(id=wxID_FRAME1STATICLINE1,
    name='staticLine1', parent=self.panel1, pos=wx.Point(0, 55),
    size=wx.Size(891, 2), style=0)

    self.button2 = wx.Button(id=wxID_FRAME1BUTTON2, label=u'导出',
    name='button2', parent=self.panel1, pos=wx.Point(776, 496),
    size=wx.Size(75, 23), style=0)
    self.button2.SetFont(wx.Font(11, wx.SWISS, wx.NORMAL, wx.BOLD, False,
    u'Tahoma'))
    self.button2.Bind(wx.EVT_BUTTON, self.OnButton2Button,
    id=wxID_FRAME1BUTTON2)


    def __init__(self, parent):
    self._init_ctrls(parent)



    def reademail(self):#read email
    global psfname
    checkfile=True
    p='' #记录邮件html正文
    txtemail=''#记录邮件txt正文
    eto=''

    filename=self.textCtrl1.GetValue()
    try:
    emailfile=open(filename,'rb')
    msg=email.message_from_file(emailfile)
    subject=msg.get('subject')
    head=email.Header.Header(subject)
    dhead=email.Header.decode_header(head)
    subject=dhead[0][0]
    efrom=email.utils.parseaddr(msg.get("from"))[1]
    etime=msg.get("date")
    #判断收件人个数

    print msg.get("to")
    for tolines in msg.get("to").splitlines():
    findst=tolines.find('<') #从to中找<位置
    if findst==-1:
    eto=email.utils.parseaddr(msg.get("to"))[1]
    else:
    eto=eto+tolines[findst:]+'\n'

    #eto=email.utils.parseaddr(msg.get("to"))[1]
    ehead=' 发件人:'+efrom+'\n'+' 日 期:'+etime+'\n'+' 收件人:'+eto+'\n'+' 主 题:'+subject+'\n'

    for bodycheck in msg.walk():
    if not bodycheck.is_multipart():
    psname = bodycheck.get_param("name")

    if psname:
    psh = email.Header.Header(psname)
    psdh = email.Header.decode_header(psh)
    psfname = psdh[0][0]

    data = bodycheck.get_payload(decode=True)

    try:
    f = open(psfname, 'wb')
    except:
    #
    f = open('tempps', 'wb')

    f.write(data)
    f.close()
    else:
    data=bodycheck.get_payload(decode=True)
    p=str(data)

    emailend=ehead
    self.staticText2.SetLabel(emailend)
    self.staticText3.SetLabel(' 附 件:'+psfname)

    self.htmlWindow1.SetPage(p)
    txtemail=emailend+'正文:'+p
    checkfile=False
    except:

    tishi='文件'+'格式错误!'
    wx.MessageBox(tishi,'注意',wx.OK)

    tem=open('temps','w') # 临时文件存放


    lamp='<DIV>'+txtemail+'</DIV><DIV>'+' 附 件:'+psfname
    lamp=lamp.replace('\n','</DIV><DIV>')
    tem.write(lamp)

    tem.close()

    def OnButton1Button(self, event): #浏览
    dialog = wx.FileDialog(None, "Choose a file", os.getcwd(),"", wildcard, wx.OPEN)
    if dialog.ShowModal() == wx.ID_OK:
    aa=dialog.GetPath().encode('utf-8')
    self.textCtrl1.SetValue(aa.decode('utf-8'))
    self.reademail()
    dialog.Destroy()
    event.Skip()

    def savetotxt(self,filena):#邮件另存为txt文件
    resultfile=''
    read=file('temps').read()
    readf_con=read.replace('&nbsp;','\n')
    readf_con=readf_con.replace('&#187;','\n')
    readf_con=re.sub("<!--.+?-->",'\n',readf_con)
    readf_con=re.sub("<.*?>",'\n',readf_con)
    readf_con=re.sub('\n+','\n',readf_con)
    for tt in readf_con.splitlines():
    tt=tt.rstrip()+'\n'
    resultfile=resultfile+tt #去除temps文件中多余的空行

    w=open(filena,'w')

    w.write(resultfile)
    w.close()


    def OnButton2Button(self, event):#eml另存为
    wid = "text file (*.txt)|*.txt"
    savedialog = wx.FileDialog(None, "Choose a file", os.getcwd(),"", wid, wx.SAVE)
    if savedialog.ShowModal() == wx.ID_OK:
    fil=savedialog.GetPath().encode('utf-8')
    savef=fil.decode('utf-8')
    savedialog.Destroy()
    savep=os.path.dirname(savef)

    #将附件另存到该目录下
    checkdot=psfname.find('.')
    if checkdot!= -1:#判断是否存在附件
    kzhname='ps'+psfname[checkdot:]
    psfile=os.path.join(savep,kzhname)
    shutil.copy(psfname, psfile)
    self.savetotxt(savef)#存eml正文

    event.Skip()




    class App(wx.App):
    def OnInit(self):
    self.main=create(None)
    self.main.Show()
    self.SetTopWindow(self.main)
    return True
    def main():
    application=App(0)
    application.MainLoop()

    if __name__=='__main__':
    main()



  • 相关阅读:
    C#如何用OpenFileDialog控件打开图片显示到PictureBox这个控件
    C# winform 禁止窗体移动
    linux 硬链接和软链接(转)
    linux 源码编译(转)
    linux 压缩与解压缩
    硬盘分区(来自百度百科)
    arp:地址解析协议(Address Resolution Protocol)(来自维基百科)
    c++学习笔记(1)
    ProbS CF matlab源代码(二分系统)(原创作品,转载注明出处,谢谢!)
    [eclipse]UML之AmaterasUML 插件
  • 原文地址:https://www.cnblogs.com/xiaowuyi/p/2432862.html
Copyright © 2020-2023  润新知