美文网首页
POP接收邮件

POP接收邮件

作者: SimonJoe246 | 来源:发表于2018-03-07 09:46 被阅读0次

    邮件收取流程

    由上篇文章我们已经得知邮件从发送到接收的过程:

    发件人->MUA->MTA->若干MTA->MDA->MUA->收件人

    本节接收邮件主要就是编写一个MUA客户端,从MDA将邮件取回本地。

    收取邮件最常用的是POP协议,目前版本是第三版,也称POP3。python内置了poplib模块,支持POP3协议。

    回想上一节SMTP,我们对要发送的邮件内容进行了各种编码,包括添加MIME header,编码之后再进行发送。

    因此,我们通过POP3协议接收的也不是原内容,而是经过一系列编码等处理的文本。

    所以,要想把POP3收取的文本变为可阅读的邮件对象,就需要利用email模块对原始邮件进行解析。

    所以,邮件收取的流程就是:

    1. 使用poplib模块接收邮件

    2. 使用email模块解析邮件

    由上一篇文章最后总结部分可知。邮件由字符到发送到网络经历了如下的格式转化:

    纯文本:

    str->bytes->base64->str->bytes

    二进制文件:

    binary code->base64->str->bytes

    我们解析邮件也是按这个思路,逆序解析出内容。

    接收邮件

    # 输入邮件地址,口令,和POP3服务器地址
    user = input('Email: ')
    passwd = input('Password: ')
    pop3_server = input('POP3 server:')
    
    
    # 连接到POP3服务器
    server = poplib.POP3(pop3_server)
    # debug
    server.set_debuglevel(1)
    # 打印欢迎文本
    print(server.getwelcome().decode('utf-8'))
    
    
    # 身份认证
    server.user(user)
    server.pass_(passwd)
    
    
    # stat返回邮件数量和占用空间
    print('Message: %s. Size: %s' % server.stat())
    # list()返回所有邮件的编号
    resp, mails, octets = server.list()
    # 查看返回列表
    print(mails)
    
    
    # get the lastest mail, index increased from 1
    index = len(mails)
    resp, lines, octets = server.retr(index)  # 取出最新邮件
    # lines存储了邮件的原始文本的每一行,
    # 可以获得整个邮件的原始文本:
    msg_content = b'\r\n'.join(lines).decode('utf-8')
    print('AAAA',msg_content)
    # 稍后解析出邮件:
    msg = Parser().parsestr(msg_content)
    print('BBBB', msg)
    # print content of the mail
    print_info(msg)
    server.quit()
    

    这里的decode('utf-8')先把字节流转化为字符串,再将字符串转化为message结构的对象。这步与发送邮件的as_string函数相反。

    解析邮件

    def decode_str(s):
        value, charset = decode_header(s)[0]
        if charset:
            value = value.decode(charset)
        return value
    
    
    def guess_charset(msg):
        charset = msg.get_charset()
        if charset is None:
            content_type = msg.get('Content-Type', '').lower()
            pos = content_type.find('charset=')
            if pos > 0:
                charset = content_type[pos + 8:].strip()
        return charset
    
    
    def print_info(msg, indent=0):
        if indent == 0:
            for header in ['From', 'To', 'Subject']:
                value = msg.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 (msg.is_multipart()):
            parts = msg.get_payload()
            for n, part in enumerate(parts):
                print('%spart %s' %('  '*indent, n))
                print('%s——————————————————————' %'  '*indent)
                print_info(part, indent + 1)
        else:
            content_type = msg.get_content_type()
            print(content_type)
            if content_type == 'text/plain' or content_type == 'text/html':
                content = msg.get_payload(decode=True) # 将Base64或QP解码为bytes
                charset = guess_charset(msg)
                print(charset)
                if charset:
                    content = content.decode(charset) #将bytes解码为文本
                print('%sText: %s' %('  '*indent, content))
            else:
                print('%sAttachment: %s' %('  '*indent, content_type))
    

    先从上一节结构化的msg中取出信件头,打印出来。

    如果是multipart结构,get_payload函数会返回一个包含不同part的list,然后对每一part递归调用print_info,打印子信件头和子信件内容。

    不是multipart时,之后再依据Content-Type作不同处理:

    如果是text:

    利用get_payload(decode = Ture)取出子信件的内容,decode为True,则按照Content-Transfer-Typebase64QP解码为bytes

    guess_charset猜出编码方式,之后将其解码为字符显示。

    如果不是Text对象,则为附件:

    打印出附件的Content-Type

    相关文章

      网友评论

          本文标题:POP接收邮件

          本文链接:https://www.haomeiwen.com/subject/kpthfftx.html