python使用smtp发送邮件
一、概述
与发送邮件相关的 Python 模块:
smtplib
是关于 SMTP(简单邮件传输协议)的操作模块,在发送邮件的过程中起到服务器之间互相通信的作用。
简单来说,即服务器之间通信的信息,包括信息头、信息主体等等。
举个简单的例子,当你登录邮箱,写好邮件后点击发送,这部分是由 SMTP 接管;而写邮件、添加附件是由 email 模块控制。
二、开通电子邮箱的SMTP功能
在使用脚本发邮件之前,我们需要打开自己邮箱的 SMTP 功能,各家邮箱的设置方法就不一一讲述了,具体使用时可以百度一下,下面以 163 邮箱设置为例做一个简单的演示:
三、代码操作
class MailServer: def __init__(self, address, port): self.address = address self.port = port class MailUser: def __init__(self, user, password): self.user = user self.password = password class SMTPSender: """邮件通知""" _instance = None @classmethod def get_instance(cls): """单例模式""" if SMTPSender._instance is None: SMTPSender._instance = SMTPSender() return SMTPSender._instance def __init__(self): self.message = None self.client = None self.use_ssl = False self.server = None self.user = None def set_ssl(self, is_ssl): self.use_ssl = is_ssl def set_server(self, address, port): self.server = MailServer(address, port) def set_user(self, user, password): self.user = MailUser(user, password) def __del__(self): try: if self.client: self.client.quit() self.client = None except: pass def _connect(self): """连接服务器""" if self.use_ssl: self.client = smtplib.SMTP_SSL(self.server.address, self.server.port) else: self.client = smtplib.SMTP(self.server.address, self.server.port) try: # outlook 需要starttls 否则无法发送邮件 其他的不需要 self.client.starttls() except: pass def login(self): """登录邮箱""" self.client.login(self.user.user, self.user.password) log.info("邮箱登录成功") def logout(self): if self.client: self.client.close() self.client = None def set_smtp_header(self, sender, receivers, subject, cc=[], bcc=[]): """设置协议头""" self.message['From'] = sender self.message['To'] = Header(','.join(receivers)) self.message['Subject'] = Header(subject) self.message['Cc'] = Header(','.join(cc)) self.message['Bcc'] = Header(','.join(bcc)) def set_smtp_content(self, content, content_type, encoding): """设置正文内容""" alternative = MIMEMultipart('alternative') text_html = MIMEText(content, _subtype=content_type, _charset=encoding) alternative.attach(text_html) self.message.attach(alternative) def set_smtp_attachment(self, filepath, display_name=None): """设置单个附件""" attachment = MIMEApplication(open(filepath, 'rb').read()) attachment.add_header("Content-Type", 'application/octet-stream') if display_name is None: display_name = os.path.basename(filepath) attachment.add_header('Content-Disposition', 'attachment', filename=Header(display_name).encode()) self.message.attach(attachment) def set_smtp_attachments(self, filepaths, display_names=None): """设置附件""" for i in range(len(filepaths)): filepath = filepaths[i] display_name = display_names[i] if display_names else None self.set_smtp_attachment(filepath, display_name) def create_smtp_message(self, receivers, cc=[], bcc=[], subject="", content=None, content_type='utf-8', file_paths=[], display_names=[]): """构造邮箱报文""" self.message = MIMEMultipart('mixed') self.set_smtp_header(self.user.user, receivers, subject, cc, bcc) if content: self.set_smtp_content(content, 'html', content_type) if file_paths: self.set_smtp_attachments(file_paths, display_names) def send_mail(self, subject, content='', cc=[], bcc=[], receivers=[], filenames=[]): """发送 邮件 subject、recipient、content 属于必填项 content:{ 'subject': '*标题', 'recipient': ['*收件人邮箱1', '收件人邮箱2'], 'cc': ['抄送邮箱1', ’抄送邮箱2‘], 'bcc': ['密送邮箱1', '密送邮箱2'], 'content': '*正文 支持html', 'filenames': ['文件路径列表'] } """ assert self.server, '请设置邮箱服务器信息' assert self.user, '请设置user登录信息' if not self.client: self._connect() self.login() self.create_smtp_message(receivers=receivers, cc=cc, bcc=bcc, subject=subject, content=content, file_paths=filenames) self.client.sendmail(self.user.user, receivers + cc + bcc, self.message.as_string())
根据对应信息设置
instance = SMTPSender.get_instance() instance.set_server(email_info.get("邮箱服务器地址"), int(email_info.get("邮箱服务器端口"))) instance.set_user(email_info.get("邮箱账号"), email_info.get("邮箱密码")) instance.set_ssl(True) SMTPSender.get_instance().logout()