標籤:python 電子郵件 smtp 附件 發送html
由於工作中經常需要收發電子郵件,例如每日(周)的工作報告,測試報告,監控警示,定時提醒等等,大都已電子郵件的形式發送。本文將實現一個 Python 的電子郵件發送類,支援發送多個附件(目錄),HTML或純文字內容,抄送收件者,多個接收者等功能。
代碼實現
#!/usr/bin/env python# -*- coding: utf-8 -*-'''Copyright (C) 2015 By Thomas Hu. All rights reserved.@author : Thomas Hu@version: 1.0@created: 2015-05-17'''import base64import httplibimport reimport osimport smtplibfrom xml.etree import ElementTreefrom email.utils import formatdatefrom email.MIMEText import MIMETextfrom email.MIMEBase import MIMEBasefrom email.MIMEMultipart import MIMEMultipartfrom email import Encodersclass EmailSender(object): def __init__(self, smtp_server, smtp_port=0, verbose=False, debug_level=1, encoding="utf-8"): ''' Initiate the EmailSender. @param smtp_server: the Email SMTP server. @param smtp_port: the Email SMTP server port, if use the default port(25), you can set it to 0 or 25. @param verbose: show the processing information if set to 'True', default is 'False'. @param debug_level: set the smtplib debug level, if it's '0', will enable debug information. @param encoding: the encoding or charset for email body text or attachment file name, default is "utf-8". ''' self.server = smtp_server self.port = int(smtp_port) self.verbose = verbose self.debug_level = int(debug_level) self.encoding = encoding self.attachments = [] #Create smtp instance self.smtp = smtplib.SMTP(self.server, self.port) self.smtp.set_debuglevel(self.debug_level) self.print_verbose("Init SMTP server successfully. server=%s, port=%d."%(self.server, self.port)) def print_verbose(self, message): '''Print the verbose information. @param message: the message to be print if the verbose is "True". ''' if self.verbose: print(message) def login(self, user, password): '''Login to SMTP server. @param user: the user name of the email sender. @param password: the passord of the user for login to SMTP server. ''' self.from_addr = user + "@" + ".".join(self.server.split(".")[1:]) try: self.print_verbose("Start to login into SMTP server.server=%s, port=%d."%(self.server, self.port)) self.smtp.login(user, password) self.print_verbose("Login into SMTP server successfully.") except Exception as ex: print("Login into SMTP server failed! Error info: %s"%(str(ex))) def __add_attachment_file(self, filename, encoding, Filter): '''Add attachment file to the attachment list. @param filename: the file name of attachment, should not be a path. @param encoding: the encode of the attachment file name. @param Filter: the file filter object, must implement 'accept(filename)' interface, and return True or False. ''' # Check if the file is acceptable by the Filter if Filter is not None: try: accept = Filter.accept(filename) except: accept = False if accept == False: return # Add the attachment to the attachment list try: basename = os.path.basename(filename) attach = MIMEBase("application", "octet-stream") attach.set_payload(open(filename, "rb").read()) #attach.add_header("Content-Disposition", "attachment;filename=%s"%(basename)) attach.add_header("Content-Disposition", "attachment", filename=(encoding, "", basename)) Encoders.encode_base64(attach) self.attachments.append(attach) self.print_verbose("Add attachment \"%s\" successfully."%(filename)) except Exception as ex: print("Add attachment file \"%s\" failed. Error info: %s."%(filename, str(ex))) def add_attachment(self, path, encoding=None, Filter=None): '''Add attachment file to the attachment list. @param path: the path of files to be added as attachment files. If is a directory, all of the files in it will be added. @param encoding: the encode of the attachment file name. @param Filter: the file filter object, must implement 'accept(filename)' interface, and return True or False. ''' if not os.path.exists(path): self.print_verbose("Warning: attachment path \"%s\" is not exists."%(path)) return charset = encoding if (encoding is not None) else self.encoding if os.path.isfile(path): return self.__add_attachment_file(path, charset, Filter) for root, dirs, files in os.walk(path): for f in files: fname = os.path.join(root, f) self.__add_attachment_file(fname, charset, Filter) def send_email(self, subject, to_addrs, cc_addrs, content, subtype="plain", charset=None): '''Send the email to the receivers. @param subject: the email's subject(title). @param to_addrs: the receivers' addresses, it's a list looks like ["[email protected]_server.com", "[email protected]_server.com"]. @param cc_addrs: the copy to receivers' addresses, has the same format as to_addrs. @param content: the email message body, it can be plain text or HTML text, which depends on the parameter 'content_type'. @param subtype: the content type, it can be "html" or "plain", default is "plain". @param charset: the charset of message content, default is "None", use the same encoding as the initial function, which default is "utf-8". @return: if send successfully, return 'True', otherwise, return 'False'. ''' charset = charset if charset is not None else self.encoding #Set the root information msg_root = MIMEMultipart("related") msg_root["Subject"] = subject msg_root["From"] = self.from_addr # You can change it to any string msg_root["To"] = ",".join(to_addrs) msg_root["CC"] = ",".join(cc_addrs) msg_root["Date"] = formatdate(localtime=True) msg_root.preamble = "This is a multi-part message in MIME format." #Encapsulate the plain and HTML of the message body into an 'alternative' part, #so message agents can decide which they want to display. msg_alt = MIMEMultipart("alternative") #Set the message content msg_txt = MIMEText(content, subtype.lower(), charset) msg_alt.attach(msg_txt) #Add the alternative part to root part. msg_root.attach(msg_alt) #Add the attachment files for attach in self.attachments: msg_root.attach(attach) #Extend the copy to addresses to to_addrs to_addrs.extend(cc_addrs) #Send the email try: self.smtp.sendmail(self.from_addr, to_addrs, msg_root.as_string()) self.print_verbose("Send email successfully.") except Exception as ex: print("Send email failed. Error info:%s"%(str(ex))) return False return True def close(self): '''Quit from the SMTP. ''' self.smtp.quit() self.print_verbose("Logout SMTP server successfully.") def test(): smtp_server = "smtp.163.com" user = "yyy" password = "yyyxxx" from_addr = "[email protected]" to_addrs = ["[email protected]"] cc_addrs = [] subject = "Email sending test" content ='Dear Friends,<p/><a href="http://blog.csdn.net/thomashtq"> Welcome to my CSDN blog!</a> <p/>Thanks a lot!' attach_files=[r"D:\temp\sendemail\attach"] emailsender = EmailSender(smtp_server, verbose=True) emailsender.login(user, password) for attach in attach_files: emailsender.add_attachment(attach, "utf-8") emailsender.send_email(subject, to_addrs, cc_addrs, content, subtype="html", charset="utf-8") emailsender.close() if __name__ == '__main__': test()
代碼中都有詳細的解釋,請原諒我用英文注釋啊,習慣了^_^。 運行時,請將 test() 函數中相關的使用者名稱、密碼、伺服器、收件者、附件列表等進行修改。也就是 test()函數中開頭那段代碼(空行之前的),根據自己的具體情況進行修改就 OK 了。
Python發送多個附件和支援HTML及純文字內容的 Email 實現