import os, smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email.header import Header
from email import encoders


class SMTPMailer:
    __host__ = {
        "host": '',
        "port": 25
    }
    __user__ = {
        "user": '',
        "pass": ''
    }
    __mail__ = {
        "fr": {"name": '', "addr": ''},
        "to": [],
        "cc": [],
        "bc": [],
        "attachs": [],
        "subject": '',
        "content": ''
    }

    def __init__(self, ssl=False, host='', port=25, user='', password='', from_name='', from_addr='', send_to=None,
                 send_cc=None, send_bc=None, subject='', content='', attachs=None):
        self.sendflag = 0
        self.ssl = ssl
        if host:
            self.host(host, port)
        if user:
            self.user(user, password)
        if from_addr:
            self.sendFrom(from_name, from_addr)
        if send_to:
            self.sendTo(send_to)
        if send_cc:
            self.sendCc(send_cc)
        if send_bc:
            self.sendBc(send_bc)
        if subject:
            self.subject(subject)
        if content:
            self.content(content)
        if attachs:
            self.attachs(attachs)

    def enableSSL(self, ch=True):
        self.ssl = ch
        return self

    def host(self, host, port):
        self.__host__["host"] = host
        self.__host__["port"] = port
        return self

    def user(self, user, password):
        self.__user__["user"] = user
        self.__user__["pass"] = password
        return self

    def sendFrom(self, name='', addr=''):
        self.__mail__["fr"]["name"] = name
        self.__mail__["fr"]["addr"] = addr
        return self

    def sendTo(self, lst):
        if isinstance(lst, str):
            lst = [lst]
        self.__mail__["to"] = lst
        return self

    def sendCc(self, lst):
        if isinstance(lst, str):
            lst = [lst]
        self.__mail__["cc"] = lst
        return self

    def sendBc(self, lst):
        if isinstance(lst, str):
            lst = [lst]
        self.__mail__["bc"] = lst
        return self

    def subject(self, text):
        if isinstance(text, str):
            self.__mail__["subject"] = text
        else:
            raise Exception('类型异常 | Type exception.')
        return self

    def content(self, text):
        if isinstance(text, str):
            self.__mail__["content"] = text
        else:
            raise Exception('类型异常 | Type exception.')
        return self

    def attachs(self, lst):
        if isinstance(lst, str):
            lst = [lst]
        for value in lst:
            if not os.path.exists(value):
                raise Exception('文件未找到 | File not found.')
        self.__mail__["attachs"] = lst
        return self

    def send(self):
        if self.sendflag:
            return {"code": 1, "message": 'Mail has been sent.'}
        message = MIMEMultipart()
        messageFrom = Header()
        messageFrom.append(self.__mail__["fr"]["name"])
        messageFrom.append('<' + self.__mail__["fr"]["addr"] + '>')
        # 发件信息
        message["From"] = messageFrom
        # 收件列表
        message["To"]  = ';'.join(self.__mail__["to"])
        # 抄送列表
        message["Cc"]  = ';'.join(self.__mail__["cc"])
        # 密送列表
        message["Bcc"] = ';'.join(self.__mail__["bc"])
        # 设置主题
        message["Subject"] = Header(self.__mail__["subject"])
        # 设置正文
        message.attach(MIMEText(self.__mail__["content"], 'html', 'utf-8'))
        # 添加附件
        for value in self.__mail__["attachs"]:
            mime = MIMEBase('application', 'octet-stream')
            mime.add_header('Content-Disposition', 'attachment', filename=os.path.basename(value))
            mime.set_payload(open(value, 'rb').read())
            encoders.encode_base64(mime)
            message.attach(mime)
        try:
            smtp = [smtplib.SMTP, smtplib.SMTP_SSL][self.ssl](self.__host__["host"], self.__host__["port"])
        except:
            return {"code": 1, "message": 'Connection failure.'}
        try:
            smtp.login(self.__user__["user"], self.__user__["pass"])
        except:
            return {"code": 1, "message": 'Authentication failed.'}
        try:
            smtp.sendmail(self.__user__["user"], self.__mail__["to"] + self.__mail__["cc"] + self.__mail__["bc"],
                          message.as_string())
            smtp.quit()
            self.sendflag = 1
            return {"code": 0, "message": ''}
        except Exception as error:
            return {"code": 1, "message": error}


if __name__ == '__main__':
    # Example.
    result = SMTPMailer(
        ssl=True,
        host='smtp.qq.com',
        port=465,
        user='',
        password='',
        from_name='云凡网络',
        from_addr='admin@fanscloud.net',
        send_to=['user01@example.com', 'user02@example.com', 'user03@example.com'],
        send_cc=['user04@example.com', 'user05@example.com'],
        send_bc=['user06@example.com'],
        subject='标题',
        content='<p>邮件发送测试</p><p><a href="https://www.baidu.com/">链接测试</a></p>',
        attachs=['./表格.xlsx', './文档.docx']
    ).send()
    print(result)
    # Example.
    mailer = SMTPMailer()
    mailer.enableSSL(True)
    mailer.host('smtp.qq.com', 465)
    mailer.user('', '')
    mailer.sendFrom('云凡网络', 'admin@example.com')
    mailer.sendTo(['user01@example.com', 'user02@example.com', 'user03@example.com'])
    mailer.sendCc(['user04@example.com', 'user05@example.com'])
    mailer.sendBc(['user06@example.com'])
    mailer.subject('标题')
    mailer.content('<p>邮件发送测试</p><p><a href="https://www.baidu.com/">链接测试</a></p>')
    mailer.attachs(['./表格.xlsx', './文档.docx'])
    result = mailer.send()
    print(result)
