文件传输协议(File Transfer Protocol, FTP)
工作流程如下。
1.客户端连接远程主机上的 FTP 服务器。
2.客户端输入用户名和密码(或“anonymous”和电子邮件地址 )。
3.客户端进行各种文件传输和信息查询操作。
4.客户端从远程 FTP 服务器退出,结束传输。
当然,这只是一般情况下的流程。有时,由于网络两边计算机的崩溃或网络的问题,会导致整个传输在完成之前就中断。 如果客户端超过 15 分钟(900 秒) 还没有响应, FTP 连接就会超时并中断。
在底层, FTP 只使用 TCP(见第 2 章),而不使用 UDP。 另外, 可以将 FTP 看作客户端/服务器编程中的特殊情况。 因为这里的客户端和服务器都使用两个套接字来通信:一个是控制和命令端口(21 号端口),另一个是数据端口(有时是 20 号端口)
说“有时”是因为 FTP 有两种模式:主动和被动。只有在主动模式下服务器才使用数据端口。在服务器把 20 号端口设置为数据端口后,它“主动”连接客户端的数据端口。而在被动模式下,服务器只是告诉客户端随机的数据端口号,客户端必须主动建立数据连接。在这种模式下, FTP 服务器在建立数据连接时是“被动”的。最后,现在已经有了一种扩展的被动模式来支持第 6 版本的因特网协议(IPv6)地址
流程:
1.连接到服务器。
2.登录。
3.发出服务请求(希望能得到响应)。
4.退出。
Pytho 伪代码:
from ftplib import FTP
f = FTP('some.ftp.server')
f.login('anonymous', '[email protected]')
:
f.quit()
FTP 对象的方法
方 法 | 描 述 |
---|---|
login(user=’anonymous’,passwd=”, acct=”) | 登录 FTP 服务器,所有参数都是可选的 |
pwd() | 获得当前工作目录 |
cwd(path) | 把当前工作目录设置为 path 所示的路径 |
dir ([path[,…[,cb]]) | 显示 path 目录里的内容,可选的参数 cb 是一个回调函数,会传递给 retrlines()方法 |
nlst ([path[,…]) | 与 dir()类似, 但返回一个文件名列表,而不是显示这些文件名 |
retrlines(cmd [, cb]) | 给定 FTP命令(如“RETR filename”),用于下载文本文件。可选的回调函数 cb 用于处理文件的每一行 |
retrbinary(cmd,cb[,bs=8192[, ra]]) | 与 retrlines()类似,只是这个指令处理二进制文件。回调函数 cb 用于处理每一块(块大小默认为 8KB)下载的数据 |
storlines(cmd, f) | 给定 FTP 命令(如“STOR filename”),用来上传文本文件。要给定一个文件对象 f |
storbinary(cmd, f[,bs=8192]) | 与 storlines()类似,只是这个指令处理二进制文件。要给定一个文件对象 f,上传块大小 bs 默认为 8KB |
rename(old, new) | 把远程文件 old 重命名为 new |
delete(path) | 删除位于 path 的远程文件 |
mkd(directory) | 创建远程目录 |
rmd(directory) | 删除远程目录 |
quit() | 关闭连接并退出 |
关于 FTP 对象的更多信息,请参阅
https://docs.python.org/3/library/ftplib.html
>>> from ftplib import FTP
>>> f = FTP('ftp.python.org')
>>> f.login('anonymous', '[email protected]')
'230 Guest login ok, access restrictions apply.'
>>> f.dir()
total 38
drwxrwxr-x 10 1075 4127 512 May 17 2000 .
drwxrwxr-x 10 1075 4127 512 May 17 2000 ..
drwxr-xr-x 3 root wheel 512 May 19 1998 bin
drwxr-sr-x 3 root 1400 512 Jun 9 1997 dev
drwxr-xr-x 3 root wheel 512 May 19 1998 etc
lrwxrwxrwx 1 root bin 7 Jun 29 1999 lib -> usr/lib
-r--r--r-- 1 guido 4127 52 Mar 24 2000 motd
drwxrwsr-x 8 1122 4127 512 May 17 2000 pub
drwxr-xr-x 5 root wheel 512 May 19 1998 usr
>>> f.retrlines('RETR motd')
Sun Microsystems Inc. SunOS 5.6 Generic August 1997
'226 Transfer complete.
>>> f.quit()
'221 Goodbye.'
import ftplib
import os
import socket
# 链接国内好像访问不了
HOST = 'ftp.mozilla.org'
DIRN = 'pub/mozilla.org/webtools'
FILE = 'bugzilla-LATEST.tar.gz'
def main():
try:
# 创建一个 FTP 对象,尝试连接到 FTP 服务器
f = ftplib.FTP(HOST)
except (socket.error, socket.gaierror) as e:
print('ERROR: cannot reach "%s"' % HOST)
return
print('***Connected to host "%s"' % HOST)
try:
# 用“anonymous”登录
f.login()
except ftplib.error_perm:
print('ERROR: cannot login anonymously')
f.quit()
return
print('*** Logged in as "anonymous"')
try:
# 转到发布目录
f.cwd(DIRN)
except ftplib.error_perm:
print('ERROR: cannot CD to "%s"' % DIRN)
f.quit()
return
print('*** Changed to "%s" folder' % DIRN)
try:
# 下载文件
f.retrbinary('RETR %s' % FILE, open(FILE, 'wb').write)
except ftplib.error_perm:
print('ERROR: cannot read file "%s"' % FILE)
os.unlink(FILE)
else:
print('*** Downloaded "%s" to CWD' % FILE)
f.quit()
if __name__ == '__main__':
main()
Usenet 新闻系统是一个全球存档的“电子公告板”。各种主题的新闻组一应俱全,从诗歌到政治,从自然语言学到计算机语言,从软件到硬件,从种植到烹饪、招聘/应聘、 音乐、魔术、 相亲等。新闻组可以面向全球,也可以只面向某个特定区域。
整个系统是一个由大量计算机组成的庞大的全球网络,计算机之间共享 Usenet 上的帖子。如果某个用户发了一个帖子到本地的 Usenet 计算机上, 这个帖子会被传播到其他相连的计算机上,再由这些计算机传到与它们相连的计算机上,直到这个帖子传播到了全世界,
每个人都收到这个帖子为止。 帖子在 Usenet 上的存活时间是有限的,这个时间可以由 Usenet系统管理员来指定,也可以为帖子指定一个过期的日期/时间。
每个系统都有一个已“订阅”的新闻组列表, 系统只接收感兴趣的新闻组里的帖子,而不是接收服务器上所有新闻组的帖子。 Usenet 新闻组的内容由提供者安排,很多服务都是公开的。但也有一些服务只允许特定用户使用,例如付费用户、 特定大学的学生等。 Usenet 系统管理员可能会进行一些设置来要求用户输入用户名和密码,管理员也可以设置是否只能上传或只能下载。
Usenet 正在逐渐退出人们的视线,主要被在线论坛替代。
NNTP 与 FTP 的操作方式相似,但更简单。在FTP 中,登录、传输数据和控制需要使用不同的端口,而 NNTP 只使用一个标准端口 119 来通信。用户向服务器发送一个请求,服务器就做出相应的响应。
关于 NNTP 的更多信息,请参阅
https://docs.python.org/3/library/nntplib.html
先看看电子邮件系统的各个组件。最重要的组件是消息传输代理(MTA)。这是在邮件交换主机上运行的服务器进程,它负责邮件的路由、队列处理和发送工作。 MTA 就是邮件从发送主机到接收主机所要经过的主机和“跳板”,所以也称为“消息传输”的“代理”。
要让所有这些工作起来, MTA 要知道两件事情:
1)如何找到消息应该到达的下一台MTA;
2)如何与另一台 MTA 通信。
第一件事由域名服务(DNS)来查找目的域名的 MX(Mail Exchange,邮件交换)来完成。查找到的可能不是最终收件人,而可能只是下一个能最终把消息送到目的地的主机。对于第二件事, MTA 怎么把消息转给其他的 MTA 呢?
为了发送电子邮件,邮件客户端必须要连接到一个 MTA, MTA 靠某种协议进行通信。MTA之间通过消息传输系统(MTS)互相通信。只有两个 MTA 都使用这个协议时,才能进行通信。在本节开始时就说过,由于以前存在很多不同的计算机系统,每个系统都使用不同的网络软件,因此这种通信很危险,具有不可预知性。更复杂的是,有的计算机使用互连的网络,而有的计算机使用调制解调器拨号,消息的发送时间也是不可预知的。这种复杂性导致了现代电子邮件的基础之一 ——简单邮件传输协议(Simple Mail Transfer Protocol, SMTP)的诞生。
1. SMTP、 ESMTP、 LMTP
SMTP 原先由已故的 Jonathan Postel(加州大学信息学院)创建,记录在 RFC 821 中,于1982 年 8 月公布,其后有一些小修改。在 1995 年 11 月,通过 RFC 1869, SMTP 增加了一些扩展服务(即 EXMTP),现在 STMP 和 ESMTP 都合并到当前的 RFC 5321 中,于 2008 年 10月公布。这里使用 STMP 同时表示 SMTP 和 ESMTP。对于一般的应用,只要能登录服务器、发送邮件、退出即可。这些都很基础。
还有其他的协议,如 LMTP(Local Mail Transfer Protocol,本地邮件传输协议),其基于SMTP 和 ESMTP,作为 RFC 2033 于 1996 年 10 月定义。 SMTP 需要有一个邮件队列,但这需要额外的存储和管理工作。而 LMTP 提供了更轻量级的系统,移除了对邮件队列的需求。但邮件需要立即发送(即不会入队)。 LMTP 服务器不暴露到外面直接与连接到因特网的邮件网关工作,以表示接收还是拒绝一条消息。而网关作为 LMTP 的队列。
2. MTA
一些实现 SMTP 的著名 MTA 包括以下几个。
开源 MTA
• Sendmail
• Postfix
• Exim
• qmail
商业 MTA
• Microsoft Exchange
• Lotus Notes Domino Mail Server
注意,虽然这些都实现了最小的 SMTP 协议需求,但其中大多数,尤其是一些商业 MTA,都在服务器中加入了协议定义之外的特有功能。
SMTP 是在因特网上的 MTA 之间消息交换的最常用 MTSMTA。用 SMTP 把电子邮件从一台(MTA)主机传送到另一台(MTA)主机。 发电子邮件时,必须要连接到一个外部 SMTP服务器,此时邮件程序是一个 SMTP 客户端。而 SMTP 服务器也因此成为消息的第一站。
过程:
1.连接到服务器。
2.登录(根据需要)。
3.发出服务请求。
4.退出。
Python 伪代码
from smtplib import SMTP
n = SMTP('smtp.yourdomain.com')
...
n.quit()
SMTP 对象常见的方法
方 法 | 描 述 |
---|---|
sendmail(from, to, msg[, mopts, ropts]) | 将 msg 从 from 发送至 to(以列表或元组表示),还可以选择性地设置 ESMTP 邮件(mopts)和收件人(ropts)选项 |
ehlo()或 helo() | 使用 EHLO 或 HELO 初始化 SMTP 或 ESMTP 服务器的会话。这是可选的,因为sendmail()会在需要时自动调用相关内容 |
starttls(keyfile=None, certfile=None) | 让服务器启用 TLS 模式。如果给定了 keyfile 或 certfile,则它们用来创建安全套接字 |
set_debuglevel(level) | 为服务器通信设置调试级别 |
quit() | 关闭连接并退出 |
login(user, passwd) | 使用用户名和密码登录 SMTP 服务器 |
Python 对 SMTP 的更多支持, 可以阅读 https://docs.python.org/3/library/smtplib.html
>>> from smtplib import SMTP as smtp
>>> s = smtp('smtp.python.is.cool')
>>> s.set_debuglevel(1)
>>> s.sendmail('[email protected]', ('[email protected]',
'[email protected]'), ''' From: [email protected]\r\nTo:
[email protected], [email protected]\r\nSubject: test
msg\r\n\r\nxxx\r\n.''')
send: 'ehlo myMac.local\r\n'
reply: '250-python.is.cool\r\n'
reply: '250-7BIT\r\n'
reply: '250-8BITMIME\r\n'
reply: '250-AUTH CRAM-MD5 LOGIN PLAIN\r\n'
reply: '250-DSN\r\n'
reply: '250-EXPN\r\n'
reply: '250-HELP\r\n'
reply: '250-NOOP\r\n'
reply: '250-PIPELINING\r\n'
reply: '250-SIZE 15728640\r\n'
reply: '250-STARTTLS\r\n'
reply: '250-VERS V05.00c++\r\n'
reply: '250 XMVP 2\r\n'
reply: retcode (250); Msg: python.is.cool
7BIT
8BITMIME
AUTH CRAM-MD5 LOGIN PLAIN
DSN
EXPN
HELP
NOOP
PIPELINING
SIZE 15728640
STARTTLS
VERS V05.00c++
XMVP 2
send: 'mail FROM: size=108\r\n'
reply: '250 ok\r\n'
reply: retcode (250); Msg: ok
send: 'rcpt TO:\r\n'
reply: '250 ok\r\n'
reply: retcode (250); Msg: ok
send: 'data\r\n'
reply: '354 ok\r\n'
reply: retcode (354); Msg: ok
data: (354, 'ok')
send: 'From: [email protected]\r\nTo:
[email protected]\r\nSubject: test msg\r\n\r\nxxx\r\n..\r\n.\r\n'
reply: '250 ok ; id=2005122623583701300or7hhe\r\n'
reply: retcode (250); Msg: ok ; id=2005122623583701300or7hhe
data: (250, 'ok ; id=2005122623583701300or7hhe')
{}
>>> s.quit()
send: 'quit\r\n'
reply: '221 python.is.cool\r\n'
reply: retcode (221); Msg: python.is.cool
第一个用于下载邮件的协议称为邮局协议(Post Office Protocal, POP),“邮局协议(POP)的目的是让用户的工作站可以访问邮箱服务器里的邮件,并在工作站中。通过简单邮件传输协议(SMTP)将邮件发送到邮件服务器”。 POP协议的最新版本是第 3 版,也称为 POP3。在 POP 出现几年之后有了一个与之竞争的协议,即因特网消息访问协议(Internet
Message Access Protocol, IMAP)。 IMAP 还有其他名称,如“因特网邮件访问协议”、“交互式邮件访问协议”、“临时邮件访问协议”。
IMAP 旨在提供比 POP 更完整的解决方案,但它也因此比 POP 更复杂。例如, IMAP 非常适合今天的需要,因为用户需要通过不同的设备使用电子邮件,如台式机、笔记本电脑、平板电脑、手机、视频游戏系统等。 POP 无法很好地应对多邮件客户端,尽管 POP 应用依然广泛,但大部分情况下已经被废弃了。
当前广泛使用的版本是 IMAP4rev1。本书中的 IMAP4 同时表示 IMAP4 和 IMAP4rev1 协议。
流程:
1.连接到服务器。
2.登录。
3.发出服务请求。
4.退出。
Python 伪代码如下
from poplib import POP3
p = POP3('pop.python.is.cool')
p.user(...)
p.pass_(...)
...
p.quit()
>>> from poplib import POP3
>>> p = POP3('pop.python.is.cool')
>>> p.user('wesley')
'+OK'
>>> p.pass_("you'llNeverGuess")
Traceback (most recent call last):
File "" , line 1, in ?
File "/usr/local/lib/python2.4/poplib.py", line 202,
in pass_
return self._shortcmd('PASS %s' % pswd)
File "/usr/local/lib/python2.4/poplib.py", line 165,
in _shortcmd
return self._getresp()
File "/usr/local/lib/python2.4/poplib.py", line 141,
in _getresp
raise error_proto(resp)
poplib.error_proto: -ERR directory status: BAD PASSWORD
>>> p.user('wesley')
'+OK'
>>> p.pass_('youllNeverGuess')
'+OK ready'
>>> p.stat()
(102, 2023455)
>>> rsp, msg, siz = p.retr(102)
>>> rsp, siz
('+OK', 480)
>>> for eachLine in msg:
... print eachLine
...
Date: Mon, 26 Dec 2005 23:58:38 +0000 (GMT)
Received: from c-42-32-25-43.smtp.python.is.cool
by python.is.cool (scmrch31) with ESMTP
id <2005122623583701300or7hhe>; Mon, 26 Dec 2005 23:58:37
+0000
From: [email protected]
To: [email protected]
Subject: test msg
xxx
.
>>> p.quit()
'+OK python.is.cool'
在登录时, user()方法不仅向服务器发送用户名,还会等待并显示服务器的响应,表示服务器正在等待输入该用户的密码。 如果 pass_()方法验证失败,会引发一个 poplib.error_proto异常。如果成功,会得到一个以“+”号开头的应答消息,如“+OK ready”,然后锁定服务器上的这个邮箱,直到调用 quit()方法为止。
POP3 对象的常用方法
方 法 | 描 述 |
---|---|
user(login) | 向服务器发送登录名,并显示服务器的响应,表示服务器正在等待输入该用户的密码 |
pass_(passwd) | 在用户使用 user()登录后,发送 passwd。如果登录失败,则抛出异常 |
stat() | 返回邮件的状态,即一个长度为 2 的元组(msg_ct, mbox_siz),分别表示消息的数量和消息的总大小(即字节数) |
list([msgnum]) | stat()的扩展,从服务器返回以三元组表示的整个消息列表(rsp, msg_list, rsp_siz),分别为服务器的响应、消息列表、返回消息的大小。如果给定了 msgnum,则只返回指定消息的数据 |
retr(msgnum) | 从服务器中得到消息的 msgnum,并设置其“已读”标志。返回一个长度为 3 的元组(rsp, msglines, msgsiz),分别为服务器的响应、消息的 msgnum 的所有行、消息的字节数 |
dele(msgnum) | 把消息 msgnum 标记为删除,大多数服务器在调用 quit()后执行删除操作 |
quit() | 注销、提交修改(如处理“已读”和“删除”标记等)、解锁邮箱、终止连接,然后退出 |
from smtplib import SMTP
from poplib import POP3
from time import sleep
SMTPSVR = 'smtp.python.is.cool'
POP3SVR = 'pop.python.is.cool'
who = '[email protected]'
body = '''\
From: %(who)s
To: %(who)s
Subject: test msg
Hello World!
''' % {'who': who}
sendSvr = SMTP(SMTPSVR)
errs = sendSvr.sendmail(who, [who], body)
sendSvr.quit()
assert len(errs) == 0, errs
sleep(10) # 等待10秒
recSvr = POP3(POP3SVR)
recSvr.user('wesley')
recSvr.pass_('youllNeverGuss')
rsp, msg, siz = recSvr.retr(recSvr.stat()[0])
sep = msg.index('')
recvBody = msg[sep + 1:]
assert body == recvBody # assert identical
流程与之前一样:
1.连接到服务器。
2.登录。
3.发出服务请求。
4.退出。
Python 伪代码:
from imaplib import IMAP4
s= IMAP4('imap.python.is.cool')
s.login(...)
...
s.close()
s.logout()
>>> s = IMAP4('imap.python.is.cool') # default port: 143
>>> s.login('wesley', 'youllneverguess')
('OK', ['LOGIN completed'])
>>> rsp, msgs = s.select('INBOX', True)
>>> rsp
>'OK'
>>> msgs
['98']
>>> rsp, data = s.fetch(msgs[0], '(RFC822)')
>>> rsp
'OK'
>>> for line in data[0][1].splitlines()[:5]:
... print line
...
Received: from mail.google.com
by mx.python.is.cool (Internet Inbound) with ESMTP id
316ED380000ED
for ; Fri, 11 Mar 2011 10:49:06 -0500 (EST)
Received: by gyb11 with SMTP id 11so125539gyb.10
for ; Fri, 11 Mar 2011 07:49:03 -0800
(PST)
>>> s.close()
('OK', ['CLOSE completed'])
>>> s.logout()
('BYE', ['IMAP4rev1 Server logging out'])
IMAP4 对象的常见方法
方 法 | 描 述 |
---|---|
close() | 关闭当前邮箱。如果访问权限不是只读,则本地删除的邮件在服务器端也会被丢弃 |
fetch(message_set, message_parts) | 获取之前由 message_set 设置的电子邮件消息状态(或使用message_parts 获取部分状态信息) |
login(user, password) | 使用指定的用户名和密码登录 |
logout() | 从服务器注销 |
noop() | ping 服务器,但不产生任何行为 |
search(charset, *criteria) | 查询邮箱中至少匹配一块 criteria 的消息。如果 charset 为 False,则默认使用 US-ASCII |
select(mailbox= ‘INBOX ‘, read-only=False) | 选择一个文件夹(默认是 INBOX),如果是只读,则不允许用户修改其中的内容 |
面是一些使用这些方法的示例。
• NOP、 NOOP 或“no operation”。这些内容表示与服务器保持连接状态。
>>> s.noop()
('OK', ['NOOP completed'])
获取某条消息的相关信息。
>>> rsp, data = s.fetch('98', '(BODY)')
>>> data[0]
'98 (BODY ("TEXT" "PLAIN" ("CHARSET" "ISO-8859-1" "FORMAT" "flowed"
"DELSP" "yes") NIL NIL "7BIT" 1267 33))'
获取某条消息的头。
>>> rsp, data = s.fetch('98', '(BODY[HEADER])')
>>> data[0][1][:45]
'Received: from mail-gy.google.com (mail-gy.go')
获取所有已读消息的 ID(也可以尝试使用“ALL”、“NEW”等)。
>>> s.search(None, 'SEEN')
('OK', ['1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 59 60 61 62
63 64 97'])
获取多条消息(使用冒号分隔,注意,右圆括号用来分隔结果)。
>>> rsp, data = s.fetch('98:100', '(BODY[TEXT])')
>>> data[0][1][:45]
'Welcome to Google Accounts. To activate your'
>>> data[2][1][:45]
'\r\n-b1_aeb1ac91493d87ea4f2aa7209f56f909\r\nCont'
>>> data[4][1][:45]
'This is a multi-part message in MIME format.'
>>> data[1], data[3], data[5]
(')', ')', ')')
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from smtplib import SMTP
# multipart alternative: text and html
def make_mpa_msg():
email = MIMEMultipart('alternative')
text = MIMEText('Hello World!\r\n', 'plain')
email.attach(text)
html = MIMEText(
'Hello World!
'
'', 'html')
email.attach(html)
return email
# nultipart: images
def make_img_msg(fn):
f = open(fn, 'r')
data = f.read()
f.close()
email = MIMEImage(data, name=fn)
email.add_header('Content-Disposition',
'attachment:filename="%s"' % fn)
return email
def sendMsg(fr, to, msg):
s = SMTP('localhost')
errs = s.sendmail(fr, to, msg)
s.quit()
if __name__ == '__main__':
SENDER = '' # todo 补全
RECIPS = [] # todo 补全
SOME_IMG_FILE = '' # todo 补全
print('Sending multipart alternative msg...')
msg = make_mpa_msg()
msg['From'] = SENDER
msg['To'] = ', '.join(RECIPS)
msg['Subject'] = 'multipart alternative test'
sendMsg(SENDER, RECIPS, msg.as_string())
print('Sending image msg...')
msg = make_img_msg(SOME_IMG_FILE)
msg['From'] = SENDER
msg['To'] = ', '.join(RECIPS)
msg['Subject'] = 'image file test'
sendMsg(SENDER, RECIPS, msg.as_string())
import email
def processMsg(entire_msg):
body = ''
# 解析消息
msg = email.message_from_string(entire_msg)
if msg.is_multipart():
# 遍历消息的附件
for part in msg.walk():
# 获得正确 MIME 类型
if part.get_content_type() == 'text/plain':
body = part.get_payload()
break
else:
body = msg.get_payload(decode=True)
else:
body = msg.get_payload(decode=True)
return body
# msg.get_payload():从消息正文中获取特定的部分。通常 decode 标记会设为 True,即邮件正文根据每个 Content-Transfer-Encoding 头解码。
Yahoo! Mail SMTP、 POP、 IMAP 示例
from io import StringIO
from imaplib import IMAP4_SSL
from platform import python_version
from poplib import POP3_SSL, error_proto
from socket import error
# SMTP_SSL added in 2.6
release = python_version()
if release > '2.6.2':
from smtplib import SMTP_SSL, SMTPServerDisconnected # fixed in 2.6.3
else:
SMTP_SSL = None
from secret import * # provides MAILBOX, PASSWD
who = "%[email protected]" % MAILBOX
from_ = who
to = [who]
headers = [
'From %s' % from_,
'To: %s' % ', '.join(to),
'Subject: test SMTP send via 587/TLS'
]
body = ['Hello', 'World!']
msg_to_be_sent = '\r\n\r\n'.join(('\r\n'.join(headers), '\r\n'.join(body)))
def getSubject(msg, default='(no subject line)'):
"""
getSubject(msg) - iterate over 'msg' looking for Subject line;
return if found otherwise 'default'
"""
for line in msg:
if line.startswith('Subject:'):
return line.rstrip()
if not line:
return default
return default
# SMTP/TLS
print("*** Doing SMTP send via TLS...")
if SMTP_SSL:
try:
s = SMTP_SSL('smtp.mail.yahoo.com', 465)
s.login(MAILBOX, PASSWD)
s.sendmail(from_, to, msg)
s.quit()
print(' SSL mail send!')
except SMTPServerDisconnected:
print(' error: server unexpectedly dis connected... try again')
else:
print(' error: SMTP_SSL requires 2.6.3+')
# POP
print('*** Doing POP recv...')
try:
s = POP3_SSL('pop.gmail.com', 995)
s.user(MAILBOX)
s.pass_(PASSWD)
rv, msg, sz = s.retr(s.stat()[0])
s.quit()
line = getSubject(msg)
print(' Received msg via POP: %r' % line)
except error_proto:
print(' error: POP for Yahoo!Mail Plus subscribers only')
# IMAP
print('*** Doing IMAP recv...')
try:
s = IMAP4_SSL('imap.gmail.com', 993)
s.login(MAILBOX, PASSWD)
rsp, msgs = s.select('INBOX', True)
rsp, data = s.fetch(msgs[0], '(RFC822)')
line = getSubject(StringIO(data[0][1]))
s.close()
s.logout()
print(' Received msg via IMAP: %r' % line)
except error:
print(' error: IMAP for Yahoo!Mail Plus subscribers only')
Gmail 的 SMTP/TLS、 SMTL/SSL、 POP、 IMAP 示例
from io import StringIO
from imaplib import IMAP4_SSL
from platform import python_version
from poplib import POP3_SSL
from smtplib import SMTP
# SMTP_SSL added in 2.6
release = python_version()
if release > '2.6.2':
from smtplib import SMTP_SSL # fixed in 2.6.3
else:
SMTP_SSL = None
from secret import * # provides MAILBOX, PASSWD
who = "%[email protected]" % MAILBOX
from_ = who
to = [who]
headers = [
'From %s' % from_,
'To: %s' % ', '.join(to),
'Subject: test SMTP send via 587/TLS'
]
body = ['Hello', 'World!']
msg_to_be_sent = '\r\n\r\n'.join(('\r\n'.join(headers), '\r\n'.join(body)))
def getSubject(msg, default='(no subject line)'):
"""
getSubject(msg) - iterate over 'msg' looking for Subject line;
return if found otherwise 'default'
"""
for line in msg:
if line.startswith('Subject:'):
return line.rstrip()
if not line:
return default
return default
# SMTP/TLS
print("*** Doing SMTP send via TLS...")
s = SMTP('smtp.gmail.com', 587)
if release < '2.6':
s.ehlo() # required in older releases
s.starttls()
if release < '2.5':
s.ehlo # required in older releases
s.login(MAILBOX, PASSWD)
s.sendmail(from_, to, msg_to_be_sent)
s.quit()
print(' TLS mail sent!')
# POP
print('*** Doing POP recv...')
s = POP3_SSL('pop.gmail.com', 995)
s.user(MAILBOX)
s.pass_(PASSWD)
rv, msg, sz = s.retr(s.stat()[0])
s.quit()
line = getSubject(msg)
print(' Received msg via POP: %r' % line)
msg_to_be_sent = msg_to_be_sent.replace('587/TLS', '465/SSL')
# SMTP/SSL
if SMTP_SSL:
print('*** Doing SMTP send via SSL')
s = SMTP_SSL('smtp.gmail.com', 465)
s.login(MAILBOX, PASSWD)
s.sendmail(from_, to, msg_to_be_sent)
s.quit()
print(' SSL mail sent!')
# IMAP
print('*** Doing IMAP recv...')
s = IMAP4_SSL('imap.gmail.com', 993)
s.login(MAILBOX, PASSWD)
rsp, msgs = s.select('INBOX', True)
rsp, data = s.fetch(msgs[0], '(RFC822)')
line=getSubject(StringIO(data[0][1]))
s.close()
s.logout()
print(' Received msg via IMAP: %r' % line)
电子邮件相关模块
模 块 包 | 描 述 |
---|---|
用于处理电子邮件的包(也支持 MIME) | |
smtpd | SMTP 服务器 |
base64 | Base-16、 32、 64 数据编码(RFC 3548) |
mhlib | 处理 MH 文件夹和消息的类 |
mailbox | 支持 mailbox 文件格式解析的类 |
mailcap | “mailcap”文件的处理模块 |
mimetools | (废弃) MIME 消息解析工具(使用上面的 email 模块) |
mimetypes | 在文件名/URL 和相关的 MIME 类型之间转换的模块 |
MimeWriter | (废弃) MIME 消息处理模块(使用上面的 email 模块) |
mimify (废弃) | MIME 消息处理工具(使用上面的 email 模块) |
quopri | 对 MIME 中引号括起来的可打印数据进行编码或解码 |
binascii | 二进制和 ASCII 转换 |
binhex | Binhex4 编码和解码支持 |
因特网客户端协议相关模块
模 块 | 描 述 |
---|---|
ftplib | FTP 协议客户端 |
xmlrpclib XML-RPC 协议客户端 | |
httplib | HTTP 和 HTTPS 协议客户端 |
imaplib | IMAP4 协议客户端 |
nntplib | NNTP 协议客户端 |
poplib | POP3 协议客户端 |
smtplib | SMTP 协议客户端 |
(^▽^)