总体来说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邮件包含多个字段。我下面的函数就可以处理,显示邮件的全部内容。
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==?= =?UTF-8?B?w4rDjMOi?=
'
>
;
>
;
>
;decode_header( mail.get(
'
subject
'
))
[(
'
Re: [python-chinese]
'
, None), (
'
¹ÃÃÃxml±à ÃëµÃÃÃÃâ
'
,
'
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
jasonnbfan 回复于:2005-07-11 20:22:35
下面说说发送邮件,其实我感觉发送比接收邮件要容易。还是使用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保持格式.
下面看看如何发带附件的邮件,和上面差不多.
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()发送就可以了,包括了主题,内容,附件.
全文完,菜鸟学习经过,仅供新手参考.
希望高手能多多指点.
jasonnbfan 回复于:2005-07-11 21:40:33
发现自己的表达能力太差,看来要多练练,大家将就着看好了。 这个星期研究Tk学会了写个GUI界面的邮件程序.学好了再上来写心得.
jasonnbfan 回复于:2005-07-11 21:44:34
最后把我写的一个简陋的,幼稚的一个字符平台的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,
'
'
))
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(
"
[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)

nfqx 回复于:2005-07-12 09:09:12
鼓励一下
bleem1998 回复于:2005-07-12 09:20:57
very good
xichen 回复于:2005-07-12 09:23:46
对于汉字编码的转换,可以这样做,我试过效果不错。 a='中国' a.decode('gb2312').encode("utf-8")
guotie 回复于:2006-06-27 11:17:03
very good !
thanks!
kai0200 回复于:2006-06-27 22:13:30
鼓励一下 帮你顶一下,向你学习!
[ 本帖最后由 kai0200 于 2006-7-4 22:22 编辑 ]
guotie 回复于:2006-08-28 14:58:22
请教一个问题,如何判断邮件的附件?
btw,楼主的showmessage()用walk()来实现似乎更好一点。
guotie 回复于:2006-08-29 14:56:54
判断某个part的编码应该使用Content-Transfer-Encoding。
guotie 回复于:2006-08-29 16:27:48
处理邮件内容时,这样做更好一些: 参数mail是通过message_from_string()得到的instance
def
mail_content(mail):
content
=
''
for
part
in
mail.walk():
if
part.is_multipart():
continue

ch
=
part.get_content_charset()
if
ch:
content
+=
unicode(part.get_payload(decode
=
True),ch).encode(
'
utf-8
'
)
else
:
content
+=
part.get_payload(decode
=
True).decode(
'
gb2312
'
).encode(
'
utf-8
'
)

return
content
|