1. POP3协议
POP3
,全名为“Post Office Protocol - Version 3”,即“邮局协议版本3”。是TCP/IP协议族中的一员,由RFC1939 定义。本协议主要用于支持使用客户端远程管理在服务器上的电子邮件
。提供了SSL加密的POP3协议被称为POP3S
。
POP 协议支持“离线”邮件处理。其具体过程是:邮件发送到服务器上,电子邮件客户端调用邮件客户机程序以连接服务器,并下载所有未阅读的电子邮件
。这种离线访问模式是一种存储转发服务,将邮件从邮件服务器端送到个人终端机器上,一般是PC机或 MAC。一旦邮件发送到 PC 机或MAC上,邮件服务器上的邮件将会被删除。但POP3邮件服务器大都可以“只下载邮件,服务器端并不删除”,也就是改进的POP3协议。
更多POP3协议,可参考以下文章:
a.
https://baike.baidu.com/item/POP3/175122?fr=aladdin
b.
https://blog.csdn.net/liuxiao723846/article/details/106588320/
c.
https://www.zhihu.com/question/356357769/answer/905014431
2. python中的pop3协议
收取邮件最常用的协议是POP协议,目前版本号是3,俗称POP3。
python内置一个poplib
模块,实现了POP3协议,可以直接用来收邮件
。
注意到POP3协议收取的不是一个已经可以阅读的邮件本身,而是邮件的原始文本,这和SMTP协议很像,SMTP发送的也是经过编码后的一大段文本。要把POP3收取的文本变成可以阅读的邮件,还需要用email模块提供的各种类来解析原始文本,变成可阅读的邮件对象
。
所以,收取邮件分两步:
第1步:
用poplib
把邮件的原始文本下载到本地;
第2步:
用email
解析原始文本,还原为邮件对象。
3. 实例
from email.parser import Parser
from email.header import decode_header
from email.utils import parseaddr
import poplib
email = '17280xxxxx@qq.com'
password = 'uluwffderhzxxxxx' # 授权码(见9-SMTP发送邮件)
pop3_server = 'pop.qq.com' # qq的POP服务器
# 解析内容, 获取编码格式
# Content-Type: text/plain; charset="utf-8"
def getCharset(msgobj):
charset = msgobj.get_charset()
if charset is None:
content_type = msgobj.get('Content-Type', '').lower()
pos = content_type.find('charset=')
if pos >= 0:
charset = content_type[pos + 8:].strip()
return charset # 'utf-8'
def decode_str(s):
value, charset = decode_header(s)[0]
if charset:
value = value.decode(charset)
return value
def parseMessageObj(msgObj, indent=0):
if indent == 0:
for header in ['From', 'To', 'Subject']:
value = msgObj.get(header, '')
if value:
if header == 'Subject':
value = decode_str(value)
else:
hdr, addr = parseaddr(value)
name = decode_str(hdr)
value = u'%s <%s>' % (name, addr)
print('%s%s: %s' % (' ' * indent, header, value))
if msgObj.is_multipart():
parts = msgObj.get_payload()
for n, part in enumerate(parts):
print('%spart %s' % (' ' * indent, n))
print('%s--------------------' % (' ' * indent))
parseMessageObj(part, indent + 1)
else:
content_type = msgObj.get_content_type()
if content_type == 'text/plain' or content_type == 'text/html':
content = msgObj.get_payload(decode=True)
charset = getCharset(msgObj)
if charset:
content = content.decode(charset)
print('%sText: %s' % (' ' * indent, content + '...'))
else:
print('%sAttachment: %s' % (' ' * indent, content_type))
def getMessageObj():
server = poplib.POP3(pop3_server) # 连接到POP3服务器
server.set_debuglevel(1) # 可以打开或关闭调试信息
print(server.getwelcome().decode('utf-8')) # 可选:打印POP3服务器的欢迎文字
server.user(email) # 邮箱号
server.pass_(password) # 授权码
numMessages, sizeMessages = server.stat() # stat()返回邮件数量和占用空间
print('>>>>>>>> Messages: {0}, Size: {1}'.format(numMessages, sizeMessages))
resp, mails, octets = server.list() # list()返回所有邮件的编号
print('>>>>>>> ', mails) # 可以查看返回的列表类似[b'1 9841', b'2 12265', ...]
# 获取最新一封邮件, 注意索引号从1开始
index = len(mails)
resp, lines, octets = server.retr(index)
# print('>>>>>> lines:', lines)
# lines存储了邮件的原始文本的每一行, 可以获得整个邮件的原始文本
rawContext = b'\r\n'.join(lines).decode('utf-8')
print('>>>>>>> rawContext:', rawContext)
# 将内容解析成Message对象
msgObj = Parser().parsestr(rawContext)
print('>>>>>> after parsestr():', msgObj)
# 关闭服务器
server.quit()
return msgObj
MsgObj = getMessageObj()
print('@@@@@@@@@@@@@@@@@@@@@@@@@@@@@')
parseMessageObj(MsgObj)