如何在Python中配置SMTPHandler以实现更高级的功能?

7 投票
4 回答
4130 浏览
提问于 2025-04-17 12:48

我正在使用标准的SMTPHandler记录器来捕捉我的Python异常。有没有办法把异常名称放到邮件的主题里呢? 这样比固定的主题要好,因为Gmail(不仅仅是Gmail)可以根据主题来归类对话,这样就可以根据错误类型来分组。

比如说,如果出现了50个完全相同的错误加上1个不同的错误,我在收件箱里就能看到两个对话,而不是一个包含51封邮件的组,这样我就很容易忽略掉那个不同的错误。

另外,有没有办法防止发送相同的错误邮件? 比如说,可以定义一个自己的函数来决定是否发送邮件。这个函数可以接收一些基本信息作为参数,这样它就能判断(例如,缓存一下,看看这个问题是否已经发送过)。

我查阅了文档,但找不到类似的内容。看起来这应该很简单。如果SMTPHandler做不到这一点,最好的简单替代方案是什么呢? 有没有什么好用的库?

谢谢!

4 个回答

0

你可以继承SMTPHandler这个类,然后增强或者替换它的功能,比如说:

class A(object):
    def __init__(self):
        self.email = "jjj@jjj.com"

    def send_error(self, error):
        send_mail(self.email, error)

class B(A):
    def __init__(self):
        A.__init__(self)

    def send_error(self, error):
        if not error.sent:
            A.send_mail(self, error)
        else:
            #do nothing
            pass
2

一个简单灵活的方法是,不仅格式化电子邮件的内容,还要格式化电子邮件的主题。这需要你创建一个新的类来继承logging.handlers.SMTPHandler

这样,如果你在主题中设置了任何变量引用,它们会在需要的时候自动展开。下面是实现的代码,包括测试代码:

    import logging, logging.handlers
    class TitledSMTPHandler(logging.handlers.SMTPHandler):
        def getSubject(self, record):
            formatter = logging.Formatter(fmt=self.subject)
            return formatter.format(record)

    # below is to test
    logging.getLogger().addHandler(TitledSMTPHandler(
        ('your.smtp.server',587), 
        'email@from.address', 'email@to.address', 
        '%(asctime)s Error: %(message)s', 
        ('SMTP login', 'SMTP password'), ()
    ))

    logging.error("TestError")

把SMTP的配置换成你自己的,运行代码后,你应该能收到一封电子邮件,邮件的主题中会包含错误信息(邮件正文中也会有)。

如果你在日志配置文件中定义了这个处理器,记得要对参数引用进行转义。例如,%(asctime)s 应该变成 %%(asctime)s,这样可以防止配置解析器提前处理——不过在Python 3.1及之前的版本中,%%的转义是不被支持的。


请你一次只问一个问题,这样会对其他搜索的人有很大帮助。你可以开两个话题,一个叫“有没有办法把异常名称放到邮件主题里?”另一个叫“有没有办法防止发送相同的错误?”

我只会回答你的第一个问题,以便专注于一个主题。也许你觉得这两个问题是相互依赖的,所以必须一起问,但它们只是同时出现在你的脑海中。我认为你可以考虑把问题的标题改成强调一个问题,而不是说“高级内容”。

我还建议你访问comp.lang.python,如果问题是开放性的或者无法很好定义(例如“我想要高级内容,大家都在用什么?”)。

9

你只需要创建一个自己的类,继承自 SMTPHandler

关于你的第一个请求:你只需要重写 getSubject(record) 这个方法。至于你可以在主题中放什么,可以在导入了 Formatter 后,查看 help(Formatter)

关于你的第二个请求:你必须重写 emit(record) 这个方法。检查记录,然后自己决定是否要发送。如果要发送,就调用 super(SMTPHandler,self).emit(record) 这个方法。

class MySMTPHandler(SMTPHandler):

    def getSubject(self, record):
        return "My Error Format from the record dict"

    def emit(self, record):
        #check for record in self.already_send or something
        if sendit:
           super(MySMTPHandler,self).emit(record)

撰写回答