如何在Python中配置SMTPHandler以实现更高级的功能?
我正在使用标准的SMTPHandler记录器来捕捉我的Python异常。有没有办法把异常名称放到邮件的主题里呢? 这样比固定的主题要好,因为Gmail(不仅仅是Gmail)可以根据主题来归类对话,这样就可以根据错误类型来分组。
比如说,如果出现了50个完全相同的错误加上1个不同的错误,我在收件箱里就能看到两个对话,而不是一个包含51封邮件的组,这样我就很容易忽略掉那个不同的错误。
另外,有没有办法防止发送相同的错误邮件? 比如说,可以定义一个自己的函数来决定是否发送邮件。这个函数可以接收一些基本信息作为参数,这样它就能判断(例如,缓存一下,看看这个问题是否已经发送过)。
我查阅了文档,但找不到类似的内容。看起来这应该很简单。如果SMTPHandler做不到这一点,最好的简单替代方案是什么呢? 有没有什么好用的库?
谢谢!
4 个回答
你可以继承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
一个简单灵活的方法是,不仅格式化电子邮件的内容,还要格式化电子邮件的主题。这需要你创建一个新的类来继承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,如果问题是开放性的或者无法很好定义(例如“我想要高级内容,大家都在用什么?”)。
你只需要创建一个自己的类,继承自 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)