[轉載]用Python處理郵件

  整體來講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郵件包含多個字段。我下面的函數就能夠處理,顯示郵件的所有內容。 python

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=?=  

  下面開始寫內容。 app

 

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)
相關文章
相關標籤/搜索