python的smtplib提供了一种很方便的途径发送电子邮件。它对smtp协议进行了简单的封装。
smtp协议的基本命令包括:
HELO 向服务器标识用户身份
MAIL 初始化邮件传输 mail from:
RCPT 标识单个的邮件接收人;常在MAIL命令后面,可有多个rcpt to:
DATA 在单个或多个RCPT命令后,表示全部的邮件接收人已标识,并初始化数据传输,以.结束
VRFY 用于验证指定的用户/邮箱是否存在;因为安全方面的缘由,服务器常禁止此命令
EXPN 验证给定的邮箱列表是否存在,扩充邮箱列表,也常被禁用
HELP 查询服务器支持什么命令
NOOP 无操做,服务器应响应OK
QUIT 结束会话
RSET 重置会话,当前传输被取消
MAIL FROM 指定发送者地址
RCPT TO 指明的接收者地址
通常smtp会话有两种方式,一种是邮件直接投递,就是说,好比你要发邮件給zzz@163.com,那就直接链接163.com的邮件服务器,把信投給zzz@163.com; 另 一种是验证事后的发信,它的过程是,好比你要发邮件給zzz@163.com,你不是直接投到163.com,而是经过本身在sina.com的另外一个邮 箱来发。这样就要先链接sina.com的smtp服务器,而后认证,以后在把要发到163.com的信件投到sina.com上,sina.com会帮 你把信投递到163.com。
第一种方式的命令流程基本是这样:
1. helo
2. mail from
3. rcpt to
4. data
5. quit
可是第一种发送方式通常有限制的,就是rcpt to指定的这个邮件接收者必须在这个服务器上存在,不然是不会接收的。 先看看代码:
#
-*- encoding: gb2312 -*-
import
os, sys, string
import
smtplib

#
邮件服务器地址
mailserver
=
"
smtp.163.com
"
#
smtp会话过程当中的mail from地址
from_addr
=
"
asfgysg@zxsdf.com
"
#
smtp会话过程当中的rcpt to地址
to_addr
=
"
zhaoweikid@163.com
"
#
信件内容
msg
=
"
test mail
"

svr
=
smtplib.SMTP(mailserver)
#
设置为调试模式,就是在会话过程当中会有输出信息
svr.set_debuglevel(
1
)
#
helo命令,docmd方法包括了获取对方服务器返回信息
svr.docmd(
"
HELO server
"
)
#
mail from, 发送邮件发送者
svr.docmd(
"
MAIL FROM: <%s>
"
%
from_addr)
#
rcpt to, 邮件接收者
svr.docmd(
"
RCPT TO: <%s>
"
%
to_addr)
#
data命令,开始发送数据
svr.docmd(
"
DATA
"
)
#
发送正文数据
svr.send(msg)
#
好比以 . 做为正文发送结束的标记,用send发送的,因此要用getreply获取返回信息
svr.send(
"
.
"
)
svr.getreply()
#
发送结束,退出
svr.quit()
注意的是,163.com是有反垃圾邮件功能的,想上面的这种投递邮件的方法不必定能经过反垃圾邮件系统的检测的。因此通常不推荐我的这样发送。
第二种有点不同:
1.ehlo
2.auth login
3.mail from
4.rcpt to
5.data
6.quit
相对于第一种来讲,多了一个认证过程,就是auth login这个过程。
#
-*- encoding: gb2312 -*-
import
os, sys, string
import
smtplib
import
base64
#
邮件服务器地址
mailserver
=
"
smtp.163.com
"
#
邮件用户名
username
=
"
xxxxxx@163.com
"
#
密码
password
=
"
xxxxxxx
"
#
smtp会话过程当中的mail from地址
from_addr
=
"
xxxxxx@163.com
"
#
smtp会话过程当中的rcpt to地址
to_addr
=
"
yyyyyy@163.com
"
#
信件内容
msg
=
"
my test mail
"
svr
=
smtplib.SMTP(mailserver)
#
设置为调试模式,就是在会话过程当中会有输出信息
svr.set_debuglevel(
1
)
#
ehlo命令,docmd方法包括了获取对方服务器返回信息
svr.docmd(
"
EHLO server
"
)
#
auth login 命令
svr.docmd(
"
AUTH LOGIN
"
)
#
发送用户名,是base64编码过的,用send发送的,因此要用getreply获取返回信息
svr.send(base64.encodestring(username))
svr.getreply()
#
发送密码
svr.send(base64.encodestring(password))
svr.getreply()
#
mail from, 发送邮件发送者
svr.docmd(
"
MAIL FROM: <%s>
"
%
from_addr)
#
rcpt to, 邮件接收者
svr.docmd(
"
RCPT TO: <%s>
"
%
to_addr)
#
data命令,开始发送数据
svr.docmd(
"
DATA
"
)
#
发送正文数据
svr.send(msg)
#
好比以 . 做为正文发送结束的标记
svr.send(
"
.
"
)
svr.getreply()
#
发送结束,退出
svr.quit()
上面说的是最普通的状况,可是不能忽略的是如今好多企业邮件是支持安全邮件的,就是经过SSL发送的邮件,这个怎么发呢?SMTP对SSL安全邮件的支持 有两种方案,一种老的是专门开启一个465端口来接收ssl邮件,另外一种更新的作法是在标准的25端口的smtp上增长一个starttls的命令来支 持。
看看第一种怎么办:
#
-*- encoding: gb2312 -*-
import
os, sys, string, socket
import
smtplib
class
SMTP_SSL (smtplib.SMTP):
def
__init__
(self, host
=
''
, port
=
465
, local_hostname
=
None, key
=
None, cert
=
None):
self.cert
=
cert
self.key
=
key
smtplib.SMTP.
__init__
(self, host, port, local_hostname)
def
connect(self, host
=
'
localhost
'
, port
=
465
):
if
not
port
and
(host.find(
'
:
'
)
==
host.rfind(
'
:
'
)):
i
=
host.rfind(
'
:
'
)
if
i
>=
0:
host, port
=
host[:i], host[i
+
1
:]
try
: port
=
int(port)
except
ValueError:
raise
socket.error,
"
nonnumeric port
"
if
not
port: port
=
654
if
self.debuglevel
>
0:
print
>>
stderr,
'
connect:
'
, (host, port)
msg
=
"
getaddrinfo returns an empty list
"
self.sock
=
None
for
res
in
socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
af, socktype, proto, canonname, sa
=
res
try
:
self.sock
=
socket.socket(af, socktype, proto)
if
self.debuglevel
>
0:
print
>>
stderr,
'
connect:
'
, (host, port)
self.sock.connect(sa)
#
新增长的建立ssl链接
sslobj
=
socket.ssl(self.sock, self.key, self.cert)
except
socket.error, msg:
if
self.debuglevel
>
0:
print
>>
stderr,
'
connect fail:
'
, (host, port)
if
self.sock:
self.sock.close()
self.sock
=
None
continue
break
if
not
self.sock:
raise
socket.error, msg
#
设置ssl
self.sock
=
smtplib.SSLFakeSocket(self.sock, sslobj)
self.file
=
smtplib.SSLFakeFile(sslobj);
(code, msg)
=
self.getreply()
if
self.debuglevel
>
0:
print
>>
stderr,
"
connect:
"
, msg
return
(code, msg)
if
__name__
==
'
__main__
'
:
smtp
=
SMTP_SSL(
'
192.168.2.10
'
)
smtp.set_debuglevel(
1
)
smtp.sendmail(
"
zzz@xxx.com
"
,
"
zhaowei@zhaowei.com
"
,
"
xxxxxxxxxxxxxxxxx
"
)
smtp.quit()
这里我是从原来的smtplib.SMTP派生出了新的SMTP_SSL类,它专门来处理ssl链接。我这里测试的192.168.2.10是我本身的测试服务器.
第二种是新增长了starttls的命令,这个很简单,smtplib里就有这个方法,叫smtplib.starttls()。固然,不是全部的邮件系 统都支持安全邮件的,这个须要从ehlo的返回值里来确认,若是里面有starttls,才表示支持。相对于发送普通邮件的第二种方法来讲,只须要新增长 一行代码就能够了:
#
-*- encoding: gb2312 -*-
import
os, sys, string
import
smtplib
import
base64
#
邮件服务器地址
mailserver
=
"
smtp.163.com
"
#
邮件用户名
username
=
"
xxxxxx@163.com
"
#
密码
password
=
"
xxxxxxx
"
#
smtp会话过程当中的mail from地址
from_addr
=
"
xxxxxx@163.com
"
#
smtp会话过程当中的rcpt to地址
to_addr
=
"
yyyyyy@163.com
"
#
信件内容
msg
=
"
my test mail
"
svr
=
smtplib.SMTP(mailserver)
#
设置为调试模式,就是在会话过程当中会有输出信息
svr.set_debuglevel(
1
)
#
ehlo命令,docmd方法包括了获取对方服务器返回信息,若是支持安全邮件,返回值里会有starttls提示
svr.docmd(
"
EHLO server
"
)
svr.starttls()
#
<------ 这行就是新加的支持安全邮件的代码!
#
auth login 命令
svr.docmd(
"
AUTH LOGIN
"
)
#
发送用户名,是base64编码过的,用send发送的,因此要用getreply获取返回信息
svr.send(base64.encodestring(username))
svr.getreply()
#
发送密码
svr.send(base64.encodestring(password))
svr.getreply()
#
mail from, 发送邮件发送者
svr.docmd(
"
MAIL FROM: <%s>
"
%
from_addr)
#
rcpt to, 邮件接收者
svr.docmd(
"
RCPT TO: <%s>
"
%
to_addr)
#
data命令,开始发送数据
svr.docmd(
"
DATA
"
)
#
发送正文数据
svr.send(msg)
#
好比以 . 做为正文发送结束的标记
svr.send(
"
.
"
)
svr.getreply()
#
发送结束,退出
svr.quit()
注意: 以上的代码为了方便我都没有判断返回值,严格说来,是应该判断一下返回的代码的,在smtp协议中,只有返回代码是2xx或者3xx才能继续下一步,返回4xx或5xx的,都是出错了。 html
____________________________________________________________ python
python模块学习 ---- smtplib 邮件发送
在基于互联网的应用中,程序常常须要自动地发送电子邮件。如:一个网站的注册系统会在用户注册时发送一封邮件来确认注册;当用户忘记登录密码的时 候,经过邮件来取回密码。smtplib模块是python中smtp(简单邮件传输协议)的客户端实现。咱们可使用smtplib模块,轻松的发送电 子邮件。下面的例子用了不到十行代码来发送电子邮件:
这个例子够简单吧^_^!下面详细介绍stmplib模块中的类和方法。 安全
smtplib.SMTP([host[, port[, local_hostname[, timeout]]]])
SMTP类构造函数,表示与SMTP服务器之间的链接,经过这个链接咱们能够向smtp服务器发送指令,执行相关操做(如:登录、发送邮件)。 该类提供了许多方法,将在下面介绍。它的全部参数都是可选的,其中host参数表示smtp服务器主机名,上面例子中的smtp主机 为"smtp.yeah.net";port表示smtp服务的端口,默认是25;若是在建立SMTP对象的时候提供了这两个参数,在初始化的时候会自动 调用connect方法去链接服务器。
smtplib模块还提供了SMTP_SSL类和LMTP类,对它们的操做与SMTP基本一致。
smtplib.SMTP提供的方法: 服务器
SMTP.set_debuglevel(level)
设置是否为调试模式。默认为False,即非调试模式,表示不输出任何调试信息。 app
SMTP.connect([host[, port]])
链接到指定的smtp服务器。参数分别表示smpt主机和端口。注意: 也能够在host参数中指定端口号(如:smpt.yeah.net:25),这样就不必给出port参数。 socket
SMTP.docmd(cmd[, argstring])
向smtp服务器发送指令。可选参数argstring表示指令的参数。下面的例子彻底经过调用docmd方法向服务器发送指令来实现邮件的发送(在smtp.yeah.net邮件服务器上试验经过。其余邮件服务器没有试过): 函数
- import smtplib, base64, time
- userName = base64.encodestring('from').strip()
- password = base64.encodestring('password').strip()
- smtp = smtplib.SMTP()
- smtp.connect("smtp.yeah.net:25")
- print smtp.docmd('helo', 'from')
- print smtp.docmd('auth login')
- print smtp.docmd(userName)
- print smtp.docmd(password)
- print smtp.docmd('mail from:', '<from@yeah.net>')
- print smtp.docmd('rcpt to:', '<from@yeah.net>')
- #data 指令表示邮件内容
- print smtp.docmd('data')
- print smtp.docmd('''''from: from@yeah.net
- to: from@yeah.net
- subject: subject
- email body
- .
- ''')
- smtp.quit()
SMTP.helo([hostname])
使用"helo"指令向服务器确认身份。至关于告诉smtp服务器“我是谁”。 学习
SMTP.has_extn(name)
判断指定名称在服务器邮件列表中是否存在。出于安全考虑,smtp服务器每每屏蔽了该指令。 测试
SMTP.verify(address)
判断指定邮件地址是否在服务器中存在。出于安全考虑,smtp服务器每每屏蔽了该指令。 网站
SMTP.login(user, password)
登录到smtp服务器。如今几乎全部的smtp服务器,都必须在验证用户信息合法以后才容许发送邮件。
SMTP.sendmail(from_addr, to_addrs, msg[, mail_options, rcpt_options])
发送邮件。这里要注意一下第三个参数,msg是字符串,表示邮件。咱们知道邮件通常由标题,发信人,收件人,邮件内容,附件等构成,发送邮件的时候,要注意msg的格式。这个格式就是smtp协议中定义的格式。在上面的例子中,msg的值为:
这个字符串的的意思表示邮件发件人为"from@yeah.net",收件人为" to@21cn.com", 邮件标题为"test",邮件内容为"just for test"。细心的你可能会疑问:若是要发送的邮件内容很复杂,包含图片、视频、附件等内容,按照MIME的格式来拼接字符串,将是一件很是麻烦的事。不 用担忧,python已经考虑到了这点,它为咱们提供了email模块,使用该模块能够轻松的发送带图片、视频、附件等复杂内容的邮件。在介绍完 smtplib模块以后,我会简单介绍email模块的基本使用。
SMTP.quit()
断开与smtp服务器的链接,至关于发送"quit"指令。
email及其相关子模块
emial模块用来处理邮件消息,包括MIME和其余基于RFC 2822 的消息文档。使用这些模块来定义邮件的内容,是很是简单的。下面是一些经常使用的类:
classemail.mime.multipart.MIMEMultipart: 多个MIME对象的集合。
classemail.mime.audio.MIMEAudio: MIME音频对象。
classemail.mime.image.MIMEImage: MIME二进制文件对象。
classemail.mime.text.MIMEText: MIME文本对象。
看上面的解释可能会以为云里雾里,其实我对smtp, MIME的理解也很肤浅。但在大多数时候,咱们只要会用就能够了。下面是一个简单的例子来演示如何使用这些类来发送带附件的邮件:
- #coding=gbk
- import smtplib, mimetypes
- from email.mime.text import MIMEText
- from email.mime.multipart import MIMEMultipart
- from email.mime.image import MIMEImage
-
- msg = MIMEMultipart()
- msg['From'] = "from@yeah.net"
- msg['To'] = 'to@21cn.com'
- msg['Subject'] = 'email for tesing'
-
- #添加邮件内容
- txt = MIMEText("这是邮件内容~~")
- msg.attach(txt)
-
- #添加二进制附件
- fileName = r'e:/PyQt4.rar'
- ctype, encoding = mimetypes.guess_type(fileName)
- if ctype is None or encoding is not None:
- ctype = 'application/octet-stream'
- maintype, subtype = ctype.split('/', 1)
- att1 = MIMEImage((lambda f: (f.read(), f.close()))(open(fileName, 'rb'))[0], _subtype = subtype)
- att1.add_header('Content-Disposition', 'attachment', filename = fileName)
- msg.attach(att1)
-
- #发送邮件
- smtp = smtplib.SMTP()
- smtp.connect('smtp.yeah.net:25')
- smtp.login('from', '密码')
- smtp.sendmail('from@yeah.net', 'to@21cn.com', msg.as_string())
- smtp.quit()
- print '邮件发送成功'
是否是很简单。简单就是美,用最少的代码把问题解决,这就是Python。更多关于smtplib的信息,请参考Python手册 smtplib模块。
___________________________________________________
Code Example:
''' # -*- coding: cp936 -*- # 甄码农,20120307 import smtplib from email.mime.text import MIMEText mail_host = 'smtp.126.com' mail_user = 'xxx@126.com' mail_pwd = 'hellopwd' mail_to = 'xxao@gmail.com' mail_cc = 'xx@xx.com' mail_bcc = 'xx@qq.com' content = 'this is a mail sent with python' #表头信息 msg = MIMEText(content) msg['From'] = mail_user msg['Subject'] = 'this is a python test mail' msg['To'] = mail_to msg['Cc'] = mail_cc msg['Bcc'] = mail_bcc try: s = smtplib.SMTP() s.connect(mail_host) #login s.login(mail_user,mail_pwd) #send mail s.sendmail(mail_user,[mail_to,mail_cc,mail_bcc],msg.as_string()) s.close() print 'success' except Exception ,e: print e '''