Python基于smtplib实现异步发送邮件服务
基于smtplib包制作而成,但在实践中发现一个不知道算不算是smtplib留的一个坑,在网络断开的情况下发送邮件时会抛出一个socket.gaierror的异常,但是smtplib中并没有捕获这个异常,导致程序会因这个异常终止,因此代码中针对这部分的异常进行处理,确保不会异常终止。
#!/usr/bin/envpython #-*-coding:utf-8-*- __author__='ZoaChou' #seehttp://www.mudoom.com/Article/show/id/29.htmlfordetail importlogging importsmtplib importmimetypes importsocket fromemailimportencoders fromemail.headerimportHeader fromemail.mime.textimportMIMEText,MIMENonMultipart fromemail.mime.baseimportMIMEBase fromemail.utilsimportparseaddr,formataddr classMailer(object): def__init__(self): pass defsend_mail(self,smtp_server,from_address,to_address,subject,body,files=None): """ 发送邮件主程序 :paramsmtp_server:dict邮件服务器设置 :keywordhost:stringsmtp服务器地址 :keywordport:intsmtp服务器端口号 :keyworduser:string用户名 :keywordpasswd:string密码 :keywordssl:bool是否启用ssl,默认False :keywordtimeout:int超时时间,默认10s :paramfrom_address:发件人邮箱 :paramto_address:收件人邮箱 :paramsubject:邮件标题 :parambody:邮件内容 :paramfiles:附件 :raise:NetworkError/MailerException """ #格式化邮件内容 body=self._encode_utf8(body) #邮件类型 content_type='html'ifbody.startswith('<html>')else'plain' msg=MIMENonMultipart()iffileselseMIMEText(body,content_type,'utf-8') #格式化邮件数据 msg['From']=self._format_address(from_address) msg['To']=','.join(self._format_list(to_address)) msg['subject']=self._encode_utf8(subject) #构造附件数据 iffiles: msg.attach(MIMEText(body,content_type,'utf-8')) cid=0 forfile_name,payloadinfiles: file_name=self._encode_utf8(file_name) main_type,sub_type=self._get_file_type(file_name) ifhasattr(payload,'read'): payload=payload.read() f_name=self._encode_header(file_name) mime=MIMEBase(main_type,sub_type,filename=f_name) mime.add_header('Content-Disposition','attachment',filename=f_name) mime.add_header('Content-ID','<%s>'%cid) mime.add_header('X-Attachment-Id','%s'%cid) mime.set_payload(payload) encoders.encode_base64(mime) msg.attach(mime) cid+=1 host=smtp_server.get('host') port=smtp_server.get('port') user=smtp_server.get('user') passwd=smtp_server.get('passwd') ssl=smtp_server.get('ssl',False) time_out=smtp_server.get('timeout',10) #没有输入端口则使用默认端口 ifportisNoneorport==0: ifssl: port=465 else: port=25 logging.debug('Sendmailform%sto%s'%(msg['From'],msg['To'])) try: ifssl: #开启ssl连接模式 server=smtplib.SMTP_SSL('%s:%d'%(host,port),timeout=time_out) else: server=smtplib.SMTP('%s:%d'%(host,port),timeout=time_out) #开启调试模式 #server.set_debuglevel(1) #如果存在用户名密码则尝试登录 ifuserandpasswd: server.login(user,passwd) #发送邮件 server.sendmail(from_address,to_address,msg.as_string()) logging.debug('Mailsentsuccess.') #关闭stmp连接 server.quit() exceptsocket.gaierror,e: """网络无法连接""" logging.exception(e) raiseNetworkError(e) exceptsmtplib.SMTPServerDisconnected,e: """网络连接异常""" logging.exception(e) raiseNetworkError(e) exceptsmtplib.SMTPException,e: """邮件发送异常""" logging.exception(e) raiseMailerException(e) def_format_address(self,s): """ 格式化邮件地址 :params:string邮件地址 :return:string格式化后的邮件地址 """ name,address=parseaddr(s) returnformataddr((self._encode_header(name),self._encode_utf8(address))) def_encode_header(self,s): """ 格式化符合MIME的头部数据 :params:string待格式化数据 :return:格式化后的数据 """ returnHeader(s,'utf-8').encode() def_encode_utf8(self,s): """ 格式化成utf-8编码 :params:string待格式化数据 :return:string格式化后的数据 """ ifisinstance(s,unicode): returns.encode('utf-8') else: returns def_get_file_type(self,file_name): """ 获取附件类型 :paramfile_name:附件文件名 :return:dict附件MIME """ s=file_name.lower() pos=s.rfind('.') ifpos==-1: return'application','octet-stream' ext=s[pos:] mime=mimetypes.types_map.get(ext,'application/octet-stream') pos=mime.find('/') ifpos==(-1): returnmime,'' returnmime[:pos],mime[pos+1:] def_format_list(self,address): """ 将收件人地址格式化成list :paramaddress:string/list收件人邮箱 :return:list收件人邮箱list """ l=address ifisinstance(l,basestring): l=[l] return[self._format_address(s)forsinl] classMailerException(Exception): """邮件发送异常类""" pass classNetworkError(MailerException): """网络异常类""" pass #testfor@qq.com if__name__=='__main__': importsys defprompt(prompt): """ 接收终端输入的数据 """ sys.stdout.write(prompt+":") returnsys.stdin.readline().strip() from_address=prompt("From(Only@qq.com)") passwd=prompt("Password") to_address=prompt("To").split(',') subject=prompt("Subject") print"Entermessage,endwith^D:" msg='' while1: line=sys.stdin.readline() ifnotline: break msg=msg+line print"Messagelengthis%d"%len(msg) #QQ邮箱默认设置 smtp_server={'host':'smtp.qq.com','port':None,'user':from_address,'passwd':passwd,'ssl':True} mailer=Mailer() try: mailer.send_mail(smtp_server,from_address,to_address,subject,msg) exceptMailerException,e: print(e)
以上所述就是本文的全部内容了,希望大家能够喜欢。