如何使用python日志记录的SMTPHandler和SSL发送电子邮件 [英] How can I send an email using python logging's SMTPHandler and SSL

查看:95
本文介绍了如何使用python日志记录的SMTPHandler和SSL发送电子邮件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个Flask应用程序,我想在其中将错误级别日志记录发送到电子邮件地址.我尝试设置典型的错误处理程序:

I'm developing a flask app in which I'd like to send error level logging to an email address. I tried setting up the typical error handler:

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

请注意,配置值是使用烧瓶邮件设置的,其中 MAIL_USE_SSL = True MAIL_PORT = 465 .

Note the configuration values are as set up using flask-mail, with MAIL_USE_SSL=True and MAIL_PORT=465.

但是,在调用错误时(故意在测试期间),我收到套接字超时错误-除了端口以外,我看不到如何告诉处理程序使用SSL.可以传递一个 secure =()参数(请参见

However, upon invoking an error (on purpose during testing) I get socket timeout errors - other than the port, I can't see how to tell the handler to use SSL. There is a secure=() parameter that can be passed (see the SMTPHandler docs) but that specifies us of TLS, not SSL.

任何线索如何做到这一点?谢谢!

Any clues how to do this? Thanks!

推荐答案

编辑-有关最新代码,请参见文章底部

感谢 Ned Deily 指出了这一点,smtplib(位于SMTPHandler下)需要特殊处理.我还发现

Figured it out with thanks to Ned Deily pointing out that smtplib (which sits under SMTPHandler) requires special treatment. I also found this post demonstrating how to do that, by overloading the SMTPHandler (in that case to fix a TLS problem).

使用 smtplib.SMTP_SSL (请参阅smtplib docs ),而不是简单的 smtplib.SMTP ,我能够使整个系统正常工作.这是我用来设置处理程序的utils/logs.py文件(这应该是文件以及电子邮件处理程序的一个很好的示例):

Using smtplib.SMTP_SSL (see smtplib docs), rather than the straightforward smtplib.SMTP, I was able to get the whole system working. This is the utils/logs.py file I use to set up the handlers (which should be a nice example of file, as well as email, handlers):

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='my@emailaddress.com',
                           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)

这是在我的应用程序文件中注册的:

This is registered in my application file with:

# 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)

评论员@EduGord无法正确发出记录.深入研究之后,基本SMTPHandler类发送邮件的方式与3年前相比有所不同.

Commenter @EduGord has had trouble emitting the record correctly. Digging deeper, the base SMTPHandler class is sending messages differently than it was 3+ years ago.

此更新的 emit()方法应该使消息正确格式化:

This updated emit() method should get the message to format correctly:

from email.message import EmailMessage
import email.utils
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 = EmailMessage()
            msg['From'] = self.fromaddr
            msg['To'] = ','.join(self.toaddrs)
            msg['Subject'] = self.getSubject(record)
            msg['Date'] = email.utils.localtime()
            msg.set_content(self.format(record))
            if self.username:
                smtp.login(self.username, self.password)
            smtp.send_message(msg, self.fromaddr, self.toaddrs)
            smtp.quit()
        except (KeyboardInterrupt, SystemExit):
            raise
        except:
            self.handleError(record)

希望这对某人有帮助!

这篇关于如何使用python日志记录的SMTPHandler和SSL发送电子邮件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆