免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 27408 | 回复: 18

用Python处理邮件,全文完. [复制链接]

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

3.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邮件包含多个字段。我下面的函数就可以处理,显示邮件的全部内容。

  1. def showmessage(mail):
  2.     if mail.is_multipart():
  3.         for part in mail.get_payload():
  4.             showmessage(part)
  5.     else:
  6.         type=mail.get_content_charset()
  7.         if type==None:
  8.             print mail.get_payload()
  9.         else:
  10.             try:
  11.                 print unicode(mail.get_payload('base64'),type)
  12.             except UnicodeDecodeError:
  13.                 print mail
复制代码


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

  1. >;>;>;mail.get('subject')
  2. 'Re: [python-chinese] =?UTF-8?B?wrnDmMOTw5p4bWzCscOgw4LDq8K1w4TDjg==?=\n\t=?UTF-8?B?w4rDjMOi?='
  3. >;>;>;decode_header( mail.get('subject'))
  4. [('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')]
  5. >;>;>;print decode_header( mail.get('subject'))[1][0]
  6. 鹿脴脫脷xml卤脿脗毛碌脛脦脢脤芒
  7. >;>;>;print unicode(decode_header( mail.get('subject'))[1][0],'utf-8')
  8. 1?óúxml±à??μ??êìa
复制代码

论坛徽章:
0
发表于 2005-07-11 20:22 |显示全部楼层

用Python处理邮件,全文完.

下面说说发送邮件,其实我感觉发送比接收邮件要容易。还是使用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=?=

下面开始写内容。
  1. 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)  #现在我们把编码好的附件也加进去

完成后的邮件像下面这样

  1. to: asdf@tom.com
  2. from: asdf@tom.com
  3. subject: =?gb2312?b?1vfM4g==?=
  4. Content-Type: multipart/mixed; boundary="===============0572491976=="
  5. MIME-Version: 1.0

  6. --===============0572491976==
  7. Content-Type: text/plain; charset="gb2312"
  8. MIME-Version: 1.0
  9. Content-Transfer-Encoding: base64

  10. 1eLA78rHxNrI3Q==

  11. --===============0572491976==
  12. Content-Type: Application/octet-stream;name="myself.py"
  13. MIME-Version: 1.0
  14. Content-Transfer-Encoding: base64
  15. Content-Disposition: attachment;filename="myself.py"

  16. ZnJvbSBlbWFpbC5NSU1FVGV4dCBpbXBvcnQgTUlNRVRleHQKZnJvbSBlbWFpbC5NSU1FTXVsdGlw
  17. YXJ0IGltcG9ydCBNSU1FTXVsdGlwYXJ0CmZyb20gZW1haWwuSGVhZGVyIGltcG9ydCBIZWFkZXIK
  18. ZnJvbSBlbWFpbC5IZWFkZXIgaW1wb3J0IGRlY29kZV9oZWFkZXIKZnJvbSB0eXBlcyBpbXBvcnQg
  19. --===============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()发送就可以了,包括了主题,内容,附件.

全文完,菜鸟学习经过,仅供新手参考.

希望高手能多多指点.

论坛徽章:
0
发表于 2005-07-11 21:40 |显示全部楼层

用Python处理邮件,全文完.

发现自己的表达能力太差,看来要多练练,大家将就着看好了。
这个星期研究Tk学会了写个GUI界面的邮件程序.学好了再上来写心得.

论坛徽章:
0
发表于 2005-07-11 21:44 |显示全部楼层

用Python处理邮件,全文完.

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

保存邮件方法没有做出来.发送邮件也没写.
  1. from email.MIMEText import MIMEText
  2. from email.MIMEMultipart import MIMEMultipart
  3. from email.Header import Header
  4. from email.Header import decode_header
  5. from types import *
  6. import smtplib,poplib,string,sys,os,email


  7. helptext = """
  8. Available commands:
  9. i     - index display
  10. l n?  - list all messages (or just message n)
  11. d n?  - mark all messages for deletion (or just message n)
  12. s n?  - save input num messages to a file (or just message n)
  13. m     - compose and send a new mail message
  14. q     - quit pymail
  15. ?     - display this help text
  16. """
  17. #简单的菜单处理,无返回值,要求一个处理过的mail列表
  18. def interact(processmail):
  19.     #showindex(processmail)
  20.     while 1:
  21.         try:
  22.             command=raw_input('[Pymail] Action? (i, l, d, s, m, q, ?) ')
  23.         except EOFError:
  24.             command='q'

  25.         if command=='q' or not command:
  26.             break

  27.         elif command[0]=='i':
  28.             showindex(processmail)

  29.         elif command[0]=='l':
  30.             if len(command)==1:
  31.                 for mail in processmail:
  32.                     showmessage(mail)
  33.                     print string.join(message)
  34.             else:
  35.                 if 0<msgnum(command)<=len(processmail):
  36.                     num=msgnum(command)
  37.                     showsubject(processmail[num-1])
  38.                     showmessage(processmail[num-1])
  39.         elif command[0]=='s':
  40.             if len(command)==1:
  41.                 print '请输入要保存的邮件号码'
  42.                 continue
  43.             else:
  44.                 if 0<msgnum(command)<=len(processmail):
  45.                     num=msgnum(command)
  46.                     savemail(processmail[num-1])

  47.         elif command[0]=='?':
  48.             print helptext

  49.         else:
  50.             print 'What? -- type "?" for commands help'

  51. #保存email未完成           
  52. def savemail(mail):
  53.     filename=raw_input('Enter a file name:')
  54.     file=open('filename','w')
  55.     print >;>; file,showsubject(mail),showmessage(mail)
  56.     print 'saving mail to %s ok.' %(filename)

  57. #处理输入的数字   
  58. def msgnum(command):
  59.     try:
  60.         return string.atoi(string.split(command)[1])
  61.     except:
  62.         return -1

  63. #用于接收 邮件的相关处理,返回一个server实例   
  64. def POPconnect():
  65.     sname,user,passwd=popconfig()
  66.     server=poplib.POP3(sname)
  67.     server.user(user)
  68.     server.pass_(passwd)
  69.     print server.getwelcome()
  70.     return server

  71. #用于发送 邮件的相关处理,返回一个server实例
  72. def SMTPconnect():
  73.     server=smtplib.SMTP(sname)
  74.     server.login(user,passwd)
  75.     return server

  76. #从服务器读取邮件到maillist.列表,位处理的原始字符串
  77. def loadmail():
  78.     server=POPconnect()
  79.     try:
  80.         print server.list()
  81.         (mailCount,mailByte)=server.stat()
  82.         print 'There are',mailCount,'mail messages in',mailByte,'bytes'
  83.         print 'Retrieving:'
  84.         mailList=[]
  85.         for i in range(mailCount):
  86.             print i+1,
  87.             (hdr,message,octet)=server.retr(i+1)
  88.             mailList.append(string.join(message,'\n'))
  89.         print
  90.         assert len(mailList)==mailCount
  91.         return mailList

  92.     finally:
  93.         server.quit()

  94. #处理loadmain返回的原始mail列表,返回处理过的processmail列表
  95. def processmail(mailList):
  96.     processmaillist=[]
  97.     for i in range(len(mailList)):
  98.         processmaillist.append(email.message_from_string(mailList[i]))
  99.     return processmaillist

  100. #显示邮件主题,要求一个处理过的mail做参数
  101. def showsubject(mail):
  102.     header=[]
  103.     for head in decode_header(mail.get('subject')):
  104.         if head[1]=='utf-8':
  105.             header.append(unicode(head[0],'utf-8'))
  106.         else:
  107.             header.append(head[0])
  108.             
  109.     for sub in ('From','Date','Subject'):
  110.         if sub=='Subject':
  111.             print 'Subject:',
  112.             for subject in header:
  113.                 try:
  114.                     print subject,
  115.                 except UnicodeEncodeError:
  116.                     print '注意:这个邮件标题无法正常显示...'
  117.         else:
  118.             print '%s:%s' %(sub,mail[sub])
  119.     print      
  120.         
  121. #显示邮件内容,要求一个处理过的mail做参数
  122. def showmessage(mail):
  123.     if mail.is_multipart():
  124.         for part in mail.get_payload():
  125.             showmessage(part)
  126.     else:
  127.         type=mail.get_content_charset()
  128.         if type==None:
  129.             print mail.get_payload()
  130.         else:
  131.             try:
  132.                 print unicode(mail.get_payload(decode='base64'),type)
  133.             except UnicodeDecodeError:
  134.                 print mail

  135. #显示全部邮件主题要求整个处理过的邮件列表
  136. def showindex(processmaillist):
  137.     count=1
  138.     for mail in processmaillist:
  139.         print count,
  140.         showsubject(mail)
  141.         print
  142.         if count%5==0:
  143.             raw_input("\n[Press Enter key]")
  144.         count+=1

  145. #输入发送时需要的服务器名等相关信息,返回一个元组
  146. def sendconfig():
  147.     SMTPname=raw_input('SMTPserverName?')
  148.     SMTPuser=raw_input('SMTPusername?')
  149.     SMTPpass=raw_input('SMTPServerPassword?')
  150.     To=raw_input('To?')
  151.     From=raw_input('From?')
  152.     return SMTPname,SMTPuser,SMTPpass,to,From

  153. #输入接收邮件时需要的相关输入,返回一个元组
  154. def popconfig():
  155.    POPname=raw_input('POPServerName?')
  156.    POPuser=raw_input('POPusername?')
  157.    POPpass=raw_input('POPpassword?')
  158.    return POPname,POPuser,POPpass

  159. if __name__=='__main__':
  160.     list=loadmail()
  161.     maillist=processmail(list)
  162.     interact(maillist)
  163.    



复制代码

论坛徽章:
0
发表于 2005-07-12 09:09 |显示全部楼层

用Python处理邮件,全文完.

鼓励一下

论坛徽章:
0
发表于 2005-07-12 09:20 |显示全部楼层

用Python处理邮件,全文完.

very good

论坛徽章:
0
发表于 2005-07-12 09:23 |显示全部楼层

用Python处理邮件,全文完.

对于汉字编码的转换,可以这样做,我试过效果不错。
a='中国'
a.decode('gb2312').encode("utf-8"

论坛徽章:
0
发表于 2006-06-27 11:17 |显示全部楼层
very good !

thanks!

论坛徽章:
0
发表于 2006-06-27 22:13 |显示全部楼层
鼓励一下
帮你顶一下,向你学习!

[ 本帖最后由 kai0200 于 2006-7-4 22:22 编辑 ]

论坛徽章:
0
发表于 2006-08-28 14:58 |显示全部楼层
请教一个问题,如何判断邮件的附件?

btw,楼主的showmessage()用walk()来实现似乎更好一点。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP