Python基於smtplib實現非同步發送郵件服務

來源:互聯網
上載者:User
基於smtplib包製作而成,但在實踐中發現一個不知道算不算是smtplib留的一個坑,在網路斷開的情況下發送郵件時會拋出一個socket.gaierror的異常,但是smtplib中並沒有捕獲這個異常,導致程式會因這個異常終止,因此代碼中針對這部分的異常進行處理,確保不會異常終止。

#!/usr/bin/env python# -*- coding: utf-8 -*-__author__ = 'Zoa Chou'# see http://www.mudoom.com/Article/show/id/29.html for detailimport loggingimport smtplibimport mimetypesimport socketfrom email import encodersfrom email.header import Headerfrom email.mime.text import MIMEText, MIMENonMultipartfrom email.mime.base import MIMEBasefrom email.utils import parseaddr, formataddrclass Mailer(object):  def __init__(self):    pass  def send_mail(self, smtp_server, from_address, to_address, subject, body, files=None):    """    發送郵件主程式    :param smtp_server: dict 郵件伺服器設定      :keyword host: string smtp伺服器位址      :keyword port: int smtp伺服器連接埠號碼      :keyword user: string 使用者名稱      :keyword passwd: string 密碼      :keyword ssl: bool 是否啟用ssl,預設False      :keyword timeout: int 逾時時間,預設10s    :param from_address: 寄件者郵箱    :param to_address: 收件者郵箱    :param subject: 郵件標題    :param body: 郵件內容    :param files: 附件    :raise: NetworkError/MailerException    """    # 格式化郵件內容    body = self._encode_utf8(body)    # 郵件類型    content_type = 'html' if body.startswith('') else 'plain'    msg = MIMENonMultipart() if files else MIMEText(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)    # 構造附件資料    if files:      msg.attach(MIMEText(body, content_type, 'utf-8'))      cid = 0      for file_name, payload in files:        file_name = self._encode_utf8(file_name)        main_type, sub_type = self._get_file_type(file_name)        if hasattr(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)    # 沒有輸入連接埠則使用預設連接埠    if port is None or port == 0:      if ssl:        port = 465      else:        port = 25    logging.debug('Send mail form %s to %s' % (msg['From'], msg['To']))    try:      if ssl:        # 開啟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)      # 如果存在使用者名稱密碼則嘗試登入      if user and passwd:        server.login(user, passwd)      # 發送郵件      server.sendmail(from_address, to_address, msg.as_string())      logging.debug('Mail sent success.')      # 關閉stmp串連      server.quit()    except socket.gaierror, e:      """ 網路無法串連 """      logging.exception(e)      raise NetworkError(e)    except smtplib.SMTPServerDisconnected, e:      """ 網路連接異常 """      logging.exception(e)      raise NetworkError(e)    except smtplib.SMTPException, e:      """ 郵件發送異常 """      logging.exception(e)      raise MailerException(e)  def _format_address(self, s):    """    格式化郵件地址    :param s:string 郵件地址    :return: string 格式化後的郵件地址    """    name, address = parseaddr(s)    return formataddr((self._encode_header(name), self._encode_utf8(address)))  def _encode_header(self, s):    """    格式化符合MIME的頭部資料    :param s: string 待格式化資料    :return: 格式化後的資料    """    return Header(s, 'utf-8').encode()  def _encode_utf8(self, s):    """    格式化成utf-8編碼    :param s: string 待格式化資料    :return: string 格式化後的資料    """    if isinstance(s, unicode):      return s.encode('utf-8')    else:      return s  def _get_file_type(self, file_name):    """    擷取附件類型    :param file_name: 附件檔案名稱    :return: dict 附件MIME    """    s = file_name.lower()    pos = s.rfind('.')    if pos == -1:      return 'application', 'octet-stream'    ext = s[pos:]    mime = mimetypes.types_map.get(ext, 'application/octet-stream')    pos = mime.find('/')    if pos == (-1):      return mime, ''    return mime[:pos], mime[pos+1:]  def _format_list(self, address):    """    將收件者地址格式化成list    :param address: string/list 收件者郵箱    :return: list 收件者郵箱list    """    l = address    if isinstance(l, basestring):      l = [l]    return [self._format_address(s) for s in l]class MailerException(Exception):  """ 郵件發送異常類 """  passclass NetworkError(MailerException):  """ 網路異常類 """  pass# test for @qq.comif __name__ == '__main__':  import sys  def prompt(prompt):    """    接收終端輸入的資料    """    sys.stdout.write(prompt + ": ")    return sys.stdin.readline().strip()  from_address = prompt("From(Only @qq.com)")  passwd = prompt("Password")  to_address = prompt("To").split(',')  subject = prompt("Subject")  print "Enter message, end with ^D:"  msg = ''  while 1:    line = sys.stdin.readline()    if not line:      break    msg = msg + line  print "Message length is %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)  except MailerException, e:    print(e)

以上所述就是本文的全部內容了,希望大家能夠喜歡。

  • 相關文章

    聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.