2016-04-29 47 views
2

我正在開發一個燒瓶應用程序,我想將錯誤級別日誌記錄發送到一個電子郵件地址。我試圖建立典型的錯誤處理程序:如何使用python logging的SMTPHandler和SSL發送電子郵件

mail_handler = SMTPHandler(mailhost=(app.config['MAIL_SERVER'], app.config['MAIL_PORT']), 
          fromaddr=app.config['MAIL_FROM_EMAIL'], 
          toaddrs=['[email protected]_address.com'], 
          subject='The server died. That sucks... :(', 
          credentials=(app.config['MAIL_USERNAME'], app.config['MAIL_PASSWORD'])) 

注意的配置值的設置使用flask-mail,與MAIL_USE_SSL=TrueMAIL_PORT=465

但是,在調用一個錯誤時(在測試期間有意),我得到套接字超時錯誤 - 除了端口之外,我看不到如何告訴處理程序使用SSL。有一個secure=()參數可以通過(請參閱the SMTPHandler docs),但它指定了我們的TLS,而不是SSL。

任何線索如何做到這一點?謝謝!

回答

5

感謝Ned Deily指出smtplib(位於SMTPHandler下)需要特殊處理。我還發現this post演示如何做到這一點,通過重載SMTPHandler(在這種情況下,以解決TLS問題)。

使用smtplib.SMTP_SSLsee smtplib docs),而不是簡單的smtplib.SMTP,我能夠得到整個系統的工作。這是我用它來建立處理器(應該是文件的一個很好的例子,以及電子郵件,處理程序)的utils的/ logs.py文件:

from your.application.file import app 

import smtplib 
import logging 
from logging.handlers import RotatingFileHandler, SMTPHandler 


# Provide a class to allow SSL (Not TLS) connection for mail handlers by overloading the emit() method 
class SSLSMTPHandler(SMTPHandler): 
    def emit(self, record): 
     """ 
     Emit a record. 
     """ 
     try: 
      port = self.mailport 
      if not port: 
       port = smtplib.SMTP_PORT 
      smtp = smtplib.SMTP_SSL(self.mailhost, port) 
      msg = self.format(record) 
      if self.username: 
       smtp.login(self.username, self.password) 
      smtp.sendmail(self.fromaddr, self.toaddrs, msg) 
      smtp.quit() 
     except (KeyboardInterrupt, SystemExit): 
      raise 
     except: 
      self.handleError(record) 


# Create file handler for error/warning/info/debug logs 
file_handler = RotatingFileHandler('logs/app.log', maxBytes=1*1024*1024, backupCount=100) 

# Apply format to the log messages 
formatter = logging.Formatter("[%(asctime)s] | %(levelname)s | {%(pathname)s:%(lineno)d} | %(message)s") 
file_handler.setFormatter(formatter) 

# Set the level according to whether we're debugging or not 
if app.debug: 
    file_handler.setLevel(logging.DEBUG) 
else: 
    file_handler.setLevel(logging.WARN) 


# Create equivalent mail handler 
mail_handler = SSLSMTPHandler(mailhost=(app.config['MAIL_SERVER'], app.config['MAIL_PORT']), 
          fromaddr=app.config['MAIL_FROM_EMAIL'], 
          toaddrs='[email protected]', 
          subject='Your app died. Sad times...', 
          credentials=(app.config['MAIL_USERNAME'], app.config['MAIL_PASSWORD'])) 

# Set the email format 
mail_handler.setFormatter(logging.Formatter(''' 
Message type:  %(levelname)s 
Location:   %(pathname)s:%(lineno)d 
Module:    %(module)s 
Function:   %(funcName)s 
Time:    %(asctime)s 

Message: 

%(message)s 
''')) 

# Only email errors, not warnings 
mail_handler.setLevel(logging.ERROR) 

這是在我的申請文件中註冊:

# Register the handlers against all the loggers we have in play 
# This is done after app configuration and SQLAlchemy initialisation, 
# drop the sqlalchemy if not using - I thought a full example would be helpful. 
import logging 
from .utils.logs import mail_handler, file_handler 
loggers = [app.logger, logging.getLogger('sqlalchemy'), logging.getLogger('werkzeug')] 
for logger in loggers: 
    logger.addHandler(file_handler) 
    # Note - I added a boolean configuration parameter, MAIL_ON_ERROR, 
    # to allow direct control over whether to email on errors. 
    # You may wish to use 'if not app.debug' instead. 
    if app.config['MAIL_ON_ERROR']: 
     logger.addHandler(mail_handler) 

希望這有助於某人!

相關問題