美文网首页Python
Python 电子邮件(SMTP、POP3)

Python 电子邮件(SMTP、POP3)

作者: _YZG_ | 来源:发表于2018-01-08 17:39 被阅读222次

    官网地址

    Python内置对SMTP的支持,可以发送纯文本邮件、HTML邮件以及带附件的邮件。
    Python对SMTP支持有smtplibemail两个模块,email负责构造邮件,smtplib负责发送邮件

    from email import encoders
    from email.header import Header
    from email.mime.text import MIMEText
    from email.utils import parseaddr, formataddr
    
    import smtplib
    
    def _format_addr(s):
        name, addr = parseaddr(s)
        print(name, addr)
        return formataddr((Header(name, 'utf-8').encode(), addr))
    
    
    # Email地址和口令
    from_addr = ''
    password = ''
    # 收件人地址
    to_addr = ''
    # SMTP服务器地址
    smtp_server = ''
    # 参数1.邮件正文  参数2MIME的subtype,plain表示纯文本,最终的MIME就是text/plain,
    # 最后一定要用utf-8编码保证多语言的兼容性
    # 如果发送HTML邮件 把HTML字符串传进去 把plain变为html
    msg = MIMEText('hello, send by Python...', 'plain', 'utf-8')
    # 注意不能简单地传入name <addr@example.com>,因为如果包含中文,需要通过Header对象进行编码。
    msg['From'] = _format_addr('Python爱好者 <%s>' % from_addr)
    # msg['To']接收的是字符串而不是list,如果有多个邮件地址,用,分隔即可。
    # 你看到的收件人的名字很可能不是我们传入的管理员,因为很多邮件服务商在显示邮件时,
    # 会把收件人名字自动替换为用户注册的名字,但是其他收件人名字的显示不受影响。
    msg['To'] = _format_addr('管理员 <%s>' % to_addr)
    msg['Subject'] = Header('来自SMTP的问候……', 'utf-8').encode()
    
    # SMTP协议默认端口是25
    server = smtplib.SMTP(smtp_server, 25)
    # 打印出和SMTP服务器交互的所有信息。
    # SMTP协议就是简单的文本命令和响应。
    #server.set_debuglevel(1)
    # 用来登录SMTP服务器
    server.login(from_addr, password)
    # 发邮件,可以发给多个人,所以是一个list,邮件正文是一个str,as_string()把MIMEText对象变成str
    server.sendmail(from_addr, [to_addr], msg.as_string())
    server.quit()
    
    

    如果要添加附件,需要构造一个MIMEMultipart

    from email.mime.multipart import MIMEMultipart
    from email.mime.base import MIMEBase
    
    # 邮件对象:
    msg = MIMEMultipart()
    msg['From'] = _format_addr('Python爱好者 <%s>' % from_addr)
    msg['To'] = _format_addr('管理员 <%s>' % to_addr)
    msg['Subject'] = Header('来自SMTP的问候……', 'utf-8').encode()
    
    # 邮件正文是MIMEText:
    msg.attach(MIMEText('send with file...', 'plain', 'utf-8'))
    
    # 添加附件就是加上一个MIMEBase,从本地读取一个图片:
    with open('/Users/yzg/Python/blur.png', 'rb') as f:
        # 设置附件的MIME和文件名,这里是png类型:
        mime = MIMEBase('image', 'png', filename='test.png')
        # 加上必要的头信息:
        mime.add_header('Content-Disposition', 'attachment', filename='test.png')
        mime.add_header('Content-ID', '<0>')
        mime.add_header('X-Attachment-Id', '0')
        # 把附件的内容读进来:
        mime.set_payload(f.read())
        # 用Base64编码:
        encoders.encode_base64(mime)
        # 添加到MIMEMultipart:
        msg.attach(mime)
    

    把图片引入正文中,只需按照发送附件的方式,先把邮件作为附件添加进去,然后,在HTML中通过引用src="cid:0"就可以把附件作为图片嵌入了。如果有多个图片,给它们依次编号,然后引用不同的cid:x即可

    msg.attach(MIMEText('<html><body><h1>Hello</h1>' +
                        '<p><img src="cid:0"></p>' +
                        '</body></html>', 'html', 'utf-8'))
    
    

    同时支持HTML和Plain格式

    msg = MIMEMultipart('alternative')
    msg['From'] = ...
    msg['To'] = ...
    msg['Subject'] = ...
    
    msg.attach(MIMEText('hello', 'plain', 'utf-8'))
    msg.attach(MIMEText('<html><body><h1>Hello</h1></body></html>', 'html', 'utf-8'))
    # 正常发送msg对象...
    

    加密SMTP

    smtp_server = 'smtp.gmail.com'
    smtp_port = 587
    server = smtplib.SMTP(smtp_server, smtp_port)
    # 只需要在创建SMTP对象后,立刻调用starttls()方法
    server.starttls()
    # 剩下的代码和前面的一模一样:
    server.set_debuglevel(1)
    ...
    

    构造一个邮件对象就是一个Messag对象,如果构造一个MIMEText对象,就表示一个文本邮件对象,如果构造一个MIMEImage对象,就表示一个作为附件的图片,要把多个对象组合起来,就用MIMEMultipart对象,而MIMEBase可以表示任何对象。它们的继承关系如下:

    Message
    +- MIMEBase
       +- MIMEMultipart
       +- MIMENonMultipart
          +- MIMEMessage
          +- MIMEText
          +- MIMEImage
    

    POP3

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    from email.parser import Parser
    from email.header import decode_header
    from email.utils import parseaddr
    
    import poplib
    
    # 输入邮件地址, 口令和POP3服务器地址:
    email = 'yzgcode@163.com'
    # 这么写灵活,我是为了方便直接写死
    password = input('Password: ')
    pop3_server = 'pop.163.com'
    
    # 文本邮件的内容也是str,还需要检测编码,否则,非UTF-8编码的邮件都无法正常显示
    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 decode_str(s):
    
    # decode_header()返回一个list  偷懒,只取了第一个元素
    
        value, charset = decode_header(s)[0]
        if charset:
            value = value.decode(charset)
        return value
    
    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()
            if content_type=='text/plain' or content_type=='text/html':
                content = msg.get_payload(decode=True)
                charset = guess_charset(msg)
                if charset:
                    content = content.decode(charset)
                print('%sText: %s' % ('  ' * indent, content + '...'))
            else:
                print('%sAttachment: %s' % ('  ' * indent, content_type))
    
    # 连接到POP3服务器:
    server = poplib.POP3(pop3_server)
    # 可以打开或关闭调试信息:
    # server.set_debuglevel(1)
    # 可选:打印POP3服务器的欢迎文字:
    print(server.getwelcome().decode('utf-8'))
    # 身份认证:
    server.user(email)
    server.pass_(password)
    # stat()返回邮件数量和占用空间:
    print('Messages: %s. Size: %s' % server.stat())
    # list()返回所有邮件的编号:
    resp, mails, octets = server.list()
    # 可以查看返回的列表类似[b'1 82923', b'2 2184', ...]
    #print(mails)
    # 获取最新一封邮件, 注意索引号从1开始:
    index = len(mails)
    resp, lines, octets = server.retr(index)
    # lines存储了邮件的原始文本的每一行,
    # 可以获得整个邮件的原始文本:
    msg_content = b'\r\n'.join(lines).decode('utf-8')
    # 稍后解析出邮件:
    msg = Parser().parsestr(msg_content)
    print_info(msg)
    # 可以根据邮件索引号直接从服务器删除邮件:
    # server.dele(index)
    # 关闭连接:
    server.quit()
    
    

    要获取所有邮件,只需要循环使用retr()把每一封邮件内容拿到即可

    相关文章

      网友评论

        本文标题:Python 电子邮件(SMTP、POP3)

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