发送邮件

# email负责构造邮件,smtplib负责发送邮件

from email import encoders
from email.header import Header
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import parseaddr, formataddr

import os

import smtplib

class EmailSender(object):

    def __init__(self, from_addr, password, server="smtp.163.com", port=25):
        # 发信人账号密码
        self.from_addr = from_addr
        self.password = password
        # 收件人地址
        self.to_addrs = []
        # SMTP服务器地址
        self.smtp_server = server
        self.smtp_port = port
        self.msg =self._get_email()
        self._add_sender(self.from_addr)

    # 添加标题
    def set_header(self, text):
        self.msg['Subject'] = Header(text, 'utf-8').encode()

    # 添加文本
    def add_text(self, text):
        self._add_content(text, "plain")

    # 添加邮件(优先)
    def add_html(self, html):
        self._add_content(html, "html")

    # 增加邮件地址
    def add_receiver(self, address):
        # msg['To'] 接收的是字符串而不是list,如果有多个邮件地址,用,分隔即可
        self.to_addrs.append(address)

    # 增加多个邮件地址
    def add_receivers(self, addresses):
        self.to_addrs.extend(addresses)

    # 添加附件
    def add_attach(self, fullname):
        # 加上一个MIMEBase,从本地读取一个图片:
        filename = os.path.basename(fullname)
        with open(fullname, 'rb') as f:
            # 设置附件的MIME和文件名,这里是png类型:
            name, ext = os.path.splitext(filename)
            ext = ext.strip(".")
            mime = MIMEBase('image', ext, filename=filename)
            # 加上必要的头信息:
            mime.add_header('Content-Disposition', 'attachment', filename=filename)
            mime.add_header('Content-ID', '<0>')
            mime.add_header('X-Attachment-Id', '0')
            # 把附件的内容读进来:
            mime.set_payload(f.read())
            # 用Base64编码:
            encoders.encode_base64(mime)
            # 添加到MIMEMultipart:
            self.msg.attach(mime)

    # 发送
    def send(self):
        self._add_receivers()

        server = smtplib.SMTP(self.smtp_server, self.smtp_port)  # SMTP协议默认端口是25
        # server.set_debuglevel(1)  # 打印出和SMTP服务器交互的所有信息
        server.login(self.from_addr, self.password)
        server.sendmail(self.from_addr, self.to_addrs, self.msg.as_string())
        server.quit()

    # 邮件对象添加内容
    def _add_content(self, text, text_type):
        # 'plain'表示纯文本, 'html'表示html文本,utf-8编码保证多语言兼容性
        self.msg.attach(MIMEText(text, text_type, 'utf-8'))

    # 格式化一个邮件地址
    def _format_addr(self, s):
        # 如果包含中文,需要通过Header对象进行编码
        name, addr = parseaddr(s)
        return formataddr((Header(name, 'utf-8').encode(), addr))

    # 获取邮件对象
    def _get_email(self):
        # 同时支持HTML和Plain格式
        return  MIMEMultipart("alternative")

    # 邮件对象添加发送者
    def _add_sender(self, from_addr):
        self.msg['From'] = self._format_addr('%s <%s>'% (from_addr, from_addr))

    # 邮件对象添加收件人
    def _add_receivers(self):
        addrs = [self._format_addr('%s <%s>' % (addr, addr)) for addr in self.to_addrs]
        self.msg['To'] = ",".join(addrs)


if __name__ == '__main__':
    email = EmailSender("xxx@163.com", "xxx")
    email.set_header("你好")
    email.add_text("hello1")
    email.add_text("hello2")
    # email.add_attach("images/guilunmei.jpeg")
    # email.add_attach("images/guilunmei.jpeg")
    email.add_receiver("mouday@qq.com")
    email.add_receiver("xxx@qq.com")
    email.send()

接收邮件

# poplib模块负责接收, email模块负责解析

from email.parser import Parser
from email.header import decode_header
from email.utils import parseaddr

import poplib

class EmailReceiver(object):

    def __init__(self, email, password, server="pop.163.com"):
    # 输入邮件地址, 口令和POP3服务器地址:
        self.email = email
        self.password = password
        self.pop3_server = server
        self._connect()
        self.message = {
            "From": None,
            "To": None,
            "Subject": None,
            "text": [],
            "attachment": []
        }  # 解析后的邮件内容



    # stat()返回邮件数量和占用空间:
    def get_stat(self):
        return self.server.stat()

    # list()返回所有邮件的编号:
    def get_list(self):
        resp, mails, octets = self.server.list()
        # 可以查看返回的列表类似[b'1 82923', b'2 2184', ...]
        return mails

    # 获取一封邮件
    def get_email(self, index):
        self._get_email(index)
        return self.message

    # 获取最新一封邮件, 注意索引号从1开始:
    def get_last_email(self):
        index = len(self.get_list())
        return self.get_email(index)

    # 连接到POP3服务器:
    def _connect(self):
        self.server = poplib.POP3(self.pop3_server)
        # 身份认证:
        self.server.user(self.email)
        self.server.pass_(self.password)

    # 可以打开或关闭调试信息:
    # server.set_debuglevel(1)

    def _get_welcome(self):
        # 可选:打印POP3服务器的欢迎文字:
        return self.server.getwelcome().decode('utf-8')

    # 获取一封邮件
    def _get_email(self, index):
        resp, lines, octets = self.server.retr(index)

        # lines存储了邮件的原始文本的每一行,
        # 可以获得整个邮件的原始文本:
        msg_content = b'\r\n'.join(lines).decode('utf-8')
        # 稍后解析出邮件:
        msg = Parser().parsestr(msg_content)

        # 可以根据邮件索引号直接从服务器删除邮件:
        # server.dele(index)
        return self._get_email_content(msg)


    def __del__(self):
        # 关闭连接:
        self.server.quit()

    # 解码
    def _decode_str(self, s):
        value, charset = decode_header(s)[0]
        if charset:
            value = value.decode(charset)
        return value

    # 获取编码
    def _guess_charset(self, 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


    # 解析邮件 indent用于缩进显示:
    def _parse_email(self, msg, indent=0):
        if indent == 0:
            for header in ['From', 'To', 'Subject']:
                value = msg.get(header, '')
                if value:
                    if header == 'Subject':
                        value = self._decode_str(value)
                    else:
                        hdr, addr = parseaddr(value)
                        name = self._decode_str(hdr)
                        value = u'%s <%s>' % (name, addr)
                self.message[header] = value

        if (msg.is_multipart()):
            parts = msg.get_payload()
            for n, part in enumerate(parts):
                self._parse_email(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 = self._guess_charset(msg)
                if charset:
                    content = content.decode(charset)
                self.message["text"].append(content)
            else:
                self.message["attachment"].append(content_type)

    # 获取邮件内容
    def _get_email_content(self, msg):
        self._parse_email(msg)
        return self.message


if __name__ == '__main__':
    email = EmailReceiver("xxx@163.com", "xxx")
    msg = email.get_last_email()
    print(msg)

项目地址:
https://github.com/mouday/email_helper

参考:
廖雪峰python 电子邮件