[转载]用Python处理邮件

此生再无相见时 提交于 2019-12-07 20:26:39

  总体来说python处理邮件还是比较方便的,库提供了很多工具.下面我把心得写出来,给新手一个启迪,也请高手给些更好的方法. 
  先说接受邮件.  poplib 方法. 
  1.poplib.POP3('这里填入你pop邮件服务器地址') 登陆服务器. 
  2.poplib.user('用户名 ') poplib.pass_('密码') 
  3.poplib.stat()方法返回一个元组:(邮件数,邮件尺寸) 
    mailCount,size=poplib.stat() 
  这样mailCount就是邮件的数量,size,就是所有邮件的大小. 

  4.poplib.rert('邮件号码')方法返回一个元组:(状态信息,邮件,邮件尺寸)  
    hdr,message,octet=server.retr(1) 读去第一个邮件信息. 
  hdr的内容就是响应信息和邮件大小比如'+OK 12498 octets' 
  message 是包含邮件所有行的列表. 
  octet 是这个邮件的内容. 

  得到的message是邮件的原始内容,也就是没有解码过的,里面的内容和标题基本上都是base64编码的,下面说说如何处理原始邮件. 
  python 的email库里提供了很多处理邮件的方法,我们先把原始邮件转成email实例,这样就可以用库方法处理邮件. 
    email.message_from_string() 这个方法能把String的邮件转换成email.message实例. 
  比如我们上面的message,向下面这样调用. 
    mail=email.message_from_string(string.join(message,'\n')) 
  这样我们就生成了一个email.Message实例 

  现在我们来提取邮件内容,和标题,mail支持字典操作.比如下面的操作. 
    mail['subject'] ,mail.get('subject') 
    mail['To'],mail.get('to')' 
    mail.keys() ,mail.items() 等等. 

  中文邮件的标题和内容都是base64编码的.解码可以使用email.Header 里的decode_header()方法. 
  比如 print mail['subject']   显示的都未处理的编码. 
'=?GB2312?B?UmU6IFtweXRob24tY2hpbmVzZV0g?=\n\t=?GB2312?B?y63E3LDvztLV0tbQzsS1xFBZVEhPTrP10afRp8+wtcTXysHP?=' 

  email.Header.decode_header(mail['subject']) 下面是解码后的信息. 
[('Re: [python-chinese] \xcb\xad\xc4\xdc\xb0\xef\xce\xd2\xd5\xd2\xd6\xd0\xce\xc4\xb5\xc4PYTHON\xb3\xf5\xd1\xa7\xd1\xa7\xcf\xb0\xb5\xc4\xd7\xca\xc1\xcf', 'gb2312')] 
返回的是一个列表,里面的内容保存在一个元组里,(解码后的字串,字符编码) 

  显示解码后的标题就象下面这样 
    print email.Header.decode_header(mail['subject'])[0][0] 
Re: [python-chinese] 谁能帮我找中文的PYTHON初学学习的资料 

  上面的mail标题编码是'gb2312'的,在我的winxp机器上可以直接显示,如果编码是别的比如'utf-8'编码,那么显示出来的就是乱码了.所以我们需要使用unicode()方法,unicode('这里是string','这里是编码,比如UTF-8'),比如 
    subject=email.Header.decode_header(mail['subject'])[0][0] 
    subcode=email.Header.decode_header(mail['subject'])[0][1]) 

    print unicode(subject,subcode) 
Re: [python-chinese] 谁能帮我找中文的PYTHON初学学习的资料 

  下面看如何处理邮件内容. 
  mail里有很多方法,熟悉这些方法处理邮件就很容易了。 
  get_payload() 这个方法可以把邮件的内容解码并且显示出来.第一个可选择参数是mail实例,第二个参数是decode='编码' ,一般都是,'base64'编码 
  is_multipart(),这个方法返回boolean值,如果实例包括多段,就返回True, 
    print mail.is_multipart() 
  true,这说明这个mail邮件包含多个字段。我下面的函数就可以处理,显示邮件的全部内容。 

def showmessage(mail):
    if mail.is_multipart():
        for part in mail.get_payload():
            showmessage(part)
    else:
        type=mail.get_content_charset()
        if type==None:
            print mail.get_payload()
        else:
            try:
                print unicode(mail.get_payload('base64'),type)
            except UnicodeDecodeError:
                print mail

  最后,有点要说明,如果邮件里的中文用mail.Header.decode_header()方法,和unicode()方法都不能正常显示,那么说明这个中文无法处理了,显示出来就是乱码.比如:看看看见,最终处理完成后,还是乱麻。 

>>>mail.get('subject')
'Re: [python-chinese] =?UTF-8?B?wrnDmMOTw5p4bWzCscOgw4LDq8K1w4TDjg==?=\n\t=?UTF-8?B?w4rDjMOi?='
>>>decode_header( mail.get('subject'))
[('Re: [python-chinese]', None), ('\xc2\xb9\xc3\x98\xc3\x93\xc3\x9axml\xc2\xb1\xc3\xa0\xc3\x82\xc3\xab\xc2\xb5\xc3\x84\xc3\x8e\xc3\x8a\xc3\x8c\xc3\xa2', 'utf-8')]
>>>print decode_header( mail.get('subject'))[1][0]
鹿脴脫脷xml卤脿脗毛碌脛脦脢脤芒
>>>print unicode(decode_header( mail.get('subject'))[1][0],'utf-8')
1?óúxml±à??μ??êìa


  下面说说发送邮件,其实我感觉发送比接收邮件要容易。还是使用mail.Message里的方法。我们一步一步来。 1:发送一个普通的文本邮件。 
    msg=mail.Message.Message()    #一个实例 
    msg['to']='love@python.com'      #发送到哪里 
    msg['from']='my@email.com'       #自己的邮件地址 
    msg['date']=time.ctime()             #时间日期 
    msg['subject']=email.Header.Header('邮件主题','gb2312') 
    #这里用Header方法处理subject. 
  完成后的样子. 
>>>print msg.as_string() 
to: love@python.com 
from: my@email.com 
date: Mon Jul 11 20:18:13 2005 
subject: =?gb2312?b?08q8/tb3zOI=?=  

  下面开始写内容。 

 

body=email.MIMEText.MIMEText('这里是邮件内容',_subtype='plain',_charset='gb2312')

  MIMEText()方法包括3个参数,内容,_subtype类型,_charset字符编码,完成后的样子: 
>>>print body.as_string() 
Content-Type: text/plain; charset="gb2312" 
MIME-Version: 1.0 
Content-Transfer-Encoding: base64 
1eLA78rHxNrI3Q== 

  Content-Type,说明内容类型,这里是txt/plain,纯文本类型。如果添加附件,那么就是Application/octet-stream 
  Content-Transfer-Encoding这个就是编码类型,这里是base64,现在的email都是base64编码 
  写完以后如何组合起来?mail有一个as_string()方法,顾名思义。显示成一个字符串.我上面也用了。smtplib里的sendmail()方法里需要的是字符串类型。所以我们这里可以这样: 完整的内容加起来就行了。 
>>>print msg.as_string()+body.as_string() 
to: love@python.com 
from: my@email.com 
date: Mon Jul 11 20:18:13 2005 
subject: =?gb2312?b?08q8/tb3zOI=?= 

Content-Type: text/plain; charset="gb2312" 
MIME-Version: 1.0 
Content-Transfer-Encoding: base64 
1eLA78rHxNrI3Q== 

  如何发送. 
    server=smtplib.SMTP('smtp.mail.yahoo.com')  #你发送服务器的地址 
    server.login('username','password')       #用户名和密码 
    server.sendmail('from','to','msg.as_string()[:-1]+body.as_string()') 
    #这样就完成了邮件的发送. 
  有一点要注意.只有内容前面有一个空行,其他的地方都不能有空行.前面我们直接print msg.as_string()+body.as_string()可以看见在subject: 和Content-type:这里有一个空行,所以我用'msg.as_string()[:-1]把多余的空行去掉.让他和body保持格式. 

  下面看看如何发带附件的邮件,和上面差不多. 
    attach=mail.MIMEMultipart.MIMEMultipart()  #这里创建一个带附件的实例 
    attach.attach(body)  #把我们刚才写的邮件内容加进去. 
    attachment=MIMEText(open('myself.py','r').read(),'base64') 
    #第一个参数打开文件read()方法读出所有内容,刚好是字符串格式,第二个参数是希望的编码,这种方法比较简单. 
    attachment.replace_header('Content-type','Application/octet-stream;name="myself.py"') 
    #前面讲过Content-type:他的值可以是text/plain text/heml 等等,如果是附件,就是Application/octet-stream,后面的;name="myself.py"是附件的文件名.默认的MIMEText()后这里的内容是text/plain的,所以需要替换 
    attachment.add_header('Content-Disposition','attachment;filename="myself.py") 
    #这里添加一个标题,Content-Disposition,attachment说明是一个附件,filename说明文件名.mail里有一个get_filename()的方法可以得到附件里的文件名. 
    attach.attach(attachment)  #现在我们把编码好的附件也加进去 

  完成后的邮件像下面这样 

to: asdf@tom.com
from: asdf@tom.com
subject: =?gb2312?b?1vfM4g==?=
Content-Type: multipart/mixed; boundary="===============0572491976=="
MIME-Version: 1.0
--===============0572491976== Content-Type: text/plain; charset="gb2312" MIME-Version: 1.0 Content-Transfer-Encoding: base64 1eLA78rHxNrI3Q== --===============0572491976== Content-Type: Application/octet-stream;name="myself.py" MIME-Version: 1.0 Content-Transfer-Encoding: base64 Content-Disposition: attachment;filename="myself.py" ZnJvbSBlbWFpbC5NSU1FVGV4dCBpbXBvcnQgTUlNRVRleHQKZnJvbSBlbWFpbC5NSU1FTXVsdGlw YXJ0IGltcG9ydCBNSU1FTXVsdGlwYXJ0CmZyb20gZW1haWwuSGVhZGVyIGltcG9ydCBIZWFkZXIK ZnJvbSBlbWFpbC5IZWFkZXIgaW1wb3J0IGRlY29kZV9oZWFkZXIKZnJvbSB0eXBlcyBpbXBvcnQg --===============0572491976==--

  好了,可以发送了. 
    server=smtplib.SMTP('smtp.mail.yahoo.com')   
    server.login('username','password')        
    server.sendmail('from','to','msg.as_string()[:-1]+attach.as_string()') 
  刚才说了,附件也可以不用MIMEText()方法创建像下面这样也可以. 
    att=base64.encodestring(open('file','r').read()) 
    att=MIMEText(att) 
  然后就和前面一样,换标题Content-type, 加Content-Disposition标题,等等.显然比较麻烦. 
  当然更简单的方法就是创建上面的attach以后,直接在attach里添加 主题等标题. 
    attach['to']='asdf@tom.com' 
    attach['from']='asdfd@tom.com' 
    attach['date']=time.ctime() 
    attach['subject']=Header('直接发送的标题','gb2312') 
  这样添加完以后直接attach.as_string()发送就可以了,包括了主题,内容,附件. 
  全文完,菜鸟学习经过,仅供新手参考. 
  希望高手能多多指点.

  最后把我写的一个简陋的,幼稚的一个字符平台的email程序贴上来.希望高手能给指点指点. 
  程序的菜单截面根据Programming Python ed2,里面的程序改的,否则我肯定是想不出来这样的菜单截面.(想象力差,还是经验不足,晕) 

  保存邮件方法没有做出来.发送邮件也没写.

from email.MIMEText import MIMEText
from email.MIMEMultipart import MIMEMultipart
from email.Header import Header
from email.Header import decode_header
from types import *
import smtplib,poplib,string,sys,os,email
helptext = """
Available commands:
i     - index display
l n?  - list all messages (or just message n)
d n?  - mark all messages for deletion (or just message n)
s n?  - save input num messages to a file (or just message n)
m     - compose and send a new mail message
q     - quit pymail
?     - display this help text
"""
#简单的菜单处理,无返回值,要求一个处理过的mail列表
def interact(processmail):
    #showindex(processmail)
    while 1:
        try:
            command=raw_input('[Pymail] Action? (i, l, d, s, m, q, ?) ')
        except EOFError:
            command='q'
        if command=='q' or not command:
            break
        elif command[0]=='i':
            showindex(processmail)
        elif command[0]=='l':
            if len(command)==1:
                for mail in processmail:
                    showmessage(mail)
                    print string.join(message)
            else:
                if 0<msgnum(command)<=len(processmail):
                    num=msgnum(command)
                    showsubject(processmail[num-1])
                    showmessage(processmail[num-1])
        elif command[0]=='s':
            if len(command)==1:
                print '请输入要保存的邮件号码'
                continue
            else:
                if 0<msgnum(command)<=len(processmail):
                    num=msgnum(command)
                    savemail(processmail[num-1])
        elif command[0]=='?':
            print helptext
        else:
            print 'What? -- type "?" for commands help'
 #保存email未完成           
def savemail(mail):
    filename=raw_input('Enter a file name:')
    file=open('filename','w')
    print >;>; file,showsubject(mail),showmessage(mail)
    print 'saving mail to %s ok.' %(filename)
#处理输入的数字   
def msgnum(command):
    try:
        return string.atoi(string.split(command)[1])
    except:
        return -1
#用于接收 邮件的相关处理,返回一个server实例   
def POPconnect():
    sname,user,passwd=popconfig()
    server=poplib.POP3(sname)
    server.user(user)
    server.pass_(passwd)
    print server.getwelcome()
    return server
#用于发送 邮件的相关处理,返回一个server实例 
def SMTPconnect():
    server=smtplib.SMTP(sname)
    server.login(user,passwd)
    return server
#从服务器读取邮件到maillist.列表,位处理的原始字符串
def loadmail():
    server=POPconnect()
    try:
        print server.list()
        (mailCount,mailByte)=server.stat()
        print 'There are',mailCount,'mail messages in',mailByte,'bytes'
        print 'Retrieving:'
        mailList=[]
        for i in range(mailCount):
            print i+1,
            (hdr,message,octet)=server.retr(i+1)
            mailList.append(string.join(message,'\n'))
        print
        assert len(mailList)==mailCount
        return mailList
    finally:
        server.quit()
#处理loadmain返回的原始mail列表,返回处理过的processmail列表
def processmail(mailList):
    processmaillist=[]
    for i in range(len(mailList)):
        processmaillist.append(email.message_from_string(mailList))
    return processmaillist
#显示邮件主题,要求一个处理过的mail做参数
def showsubject(mail):
    header=[]
    for head in decode_header(mail.get('subject')):
        if head[1]=='utf-8':
            header.append(unicode(head[0],'utf-8'))
        else:
            header.append(head[0])     for sub in ('From','Date','Subject'):
        if sub=='Subject':
            print 'Subject:',
            for subject in header:
                try:
                    print subject,
                except UnicodeEncodeError:
                    print '注意:这个邮件标题无法正常显示...'
        else:
            print '%s:%s' %(sub,mail[sub])
    print     
#显示邮件内容,要求一个处理过的mail做参数
def showmessage(mail):
    if mail.is_multipart():
        for part in mail.get_payload():
            showmessage(part)
    else:
        type=mail.get_content_charset()
        if type==None:
            print mail.get_payload()
        else:
            try:
                print unicode(mail.get_payload(decode='base64'),type)
            except UnicodeDecodeError:
                print mail
#显示全部邮件主题要求整个处理过的邮件列表
def showindex(processmaillist):
    count=1
    for mail in processmaillist:
        print count,
        showsubject(mail)
        print 
        if count%5==0:
            raw_input("\n[Press Enter key]")
        count+=1
#输入发送时需要的服务器名等相关信息,返回一个元组
def sendconfig():
    SMTPname=raw_input('SMTPserverName?')
    SMTPuser=raw_input('SMTPusername?')
    SMTPpass=raw_input('SMTPServerPassword?')
    To=raw_input('To?')
    From=raw_input('From?')
    return SMTPname,SMTPuser,SMTPpass,to,From
#输入接收邮件时需要的相关输入,返回一个元组
def popconfig():
   POPname=raw_input('POPServerName?')
   POPuser=raw_input('POPusername?')
   POPpass=raw_input('POPpassword?')
   return POPname,POPuser,POPpass
if __name__=='__main__':
    list=loadmail()
    maillist=processmail(list)
    interact(maillist)

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!