|  | import logging | 
        
          |  | import logging.handlers | 
        
          |  | import smtplib | 
        
          |  | import sys | 
        
          |  | import datetime | 
        
          |  |  | 
        
          |  |  | 
        
          |  | logging.basicConfig(stream=sys.stderr,level=logging.DEBUG,format="%(asctime)s %(name)s %(levelname)s: %(filename)s %(lineno)s: %(message)s") | 
        
          |  |  | 
        
          |  | # https://stackoverflow.com/a/36937462/2743441 | 
        
          |  | # Provide a class to allow SSL (Not TLS) connection for mail handlers by overloading the emit() method | 
        
          |  | class SSLSMTPHandler(logging.handlers.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) | 
        
          |  |  | 
        
          |  |  | 
        
          |  |  | 
        
          |  | # http://mynthon.net/howto/-/python/python%20-%20logging.SMTPHandler-how-to-use-gmail-smtp-server.txt | 
        
          |  |  | 
        
          |  | # Consider using https://github.com/Simplistix/mailinglogger/blob/master/mailinglogger/MailingLogger.py for flood prevention | 
        
          |  |  | 
        
          |  | flood_template=""" | 
        
          |  | Too Many Log Entries | 
        
          |  |  | 
        
          |  | More than %s entries have been logged that would have resulted in | 
        
          |  | emails being sent. | 
        
          |  |  | 
        
          |  | No further emails will be sent for log entries generated between | 
        
          |  | %s and %i:00:00 | 
        
          |  |  | 
        
          |  | Please consult any other configured logs, such as a File Logger, | 
        
          |  | that may contain important entries that have not been emailed. | 
        
          |  | """ | 
        
          |  |  | 
        
          |  |  | 
        
          |  |  | 
        
          |  | class TlsSMTPHandler(logging.handlers.SMTPHandler): | 
        
          |  |  | 
        
          |  |  | 
        
          |  | def __init__(self,*args,flood_level=10,**kwargs) : | 
        
          |  | super(TlsSMTPHandler, self).__init__(*args,**kwargs) | 
        
          |  | self.hour = self.now().hour | 
        
          |  | self.sent = 0 | 
        
          |  | self.flood_level = flood_level | 
        
          |  |  | 
        
          |  |  | 
        
          |  | def now(self) : | 
        
          |  | return datetime.datetime.now() | 
        
          |  |  | 
        
          |  | # https://stackoverflow.com/a/20801330/2743441 | 
        
          |  | def getSubject(self, record): | 
        
          |  | formatter = logging.Formatter(fmt=self.subject) | 
        
          |  | return formatter.format(record) | 
        
          |  |  | 
        
          |  |  | 
        
          |  |  | 
        
          |  | def emit(self, record): | 
        
          |  | """ | 
        
          |  | Emit a record. | 
        
          |  |  | 
        
          |  | Format the record and send it to the specified addressees. | 
        
          |  | """ | 
        
          |  | current_time = self.now() | 
        
          |  | current_hour = current_time.hour | 
        
          |  | if current_hour != self.hour: | 
        
          |  | self.hour = current_hour | 
        
          |  | self.sent = 0 | 
        
          |  | if self.sent == self.flood_level: | 
        
          |  | # send critical error | 
        
          |  | record = logging.LogRecord( | 
        
          |  | name='flood', | 
        
          |  | level=logging.CRITICAL, | 
        
          |  | pathname='', | 
        
          |  | lineno=0, | 
        
          |  | msg=flood_template % (self.sent, | 
        
          |  | current_time.strftime('%H:%M:%S'), | 
        
          |  | current_hour + 1), | 
        
          |  | args=(), | 
        
          |  | exc_info=None) | 
        
          |  | elif self.flood_level and self.sent > self.flood_level: | 
        
          |  | # do nothing, we've sent too many emails already | 
        
          |  | return | 
        
          |  | self.sent += 1 | 
        
          |  | try: | 
        
          |  | import smtplib | 
        
          |  | import string # for tls add this line | 
        
          |  | try: | 
        
          |  | from email.utils import formatdate | 
        
          |  | except ImportError: | 
        
          |  | formatdate = self.date_time | 
        
          |  | port = self.mailport | 
        
          |  | if not port: | 
        
          |  | port = smtplib.SMTP_PORT | 
        
          |  | smtp = smtplib.SMTP(self.mailhost, port) | 
        
          |  | msg = self.format(record) | 
        
          |  | msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\nDate: %s\r\n\r\n%s" % ( | 
        
          |  | self.fromaddr, | 
        
          |  | ",".join(self.toaddrs), | 
        
          |  | self.getSubject(record), | 
        
          |  | formatdate(), msg) | 
        
          |  | if self.username: | 
        
          |  | smtp.ehlo() # for tls add this line | 
        
          |  | smtp.starttls() # for tls add this line | 
        
          |  | smtp.ehlo() # for tls add this line | 
        
          |  | smtp.login(self.username, self.password) | 
        
          |  | smtp.sendmail(self.fromaddr, self.toaddrs, msg) | 
        
          |  | smtp.quit() | 
        
          |  | except (KeyboardInterrupt, SystemExit): | 
        
          |  | raise | 
        
          |  | except: | 
        
          |  | self.handleError(record) | 
        
          |  |  | 
        
          |  |  | 
        
          |  |  | 
        
          |  | def send_email_on(logger,level=logging.ERROR,handler=TlsSMTPHandler,flood_level=10) : | 
        
          |  | from credentials import MAILERRORS | 
        
          |  | mail_handler = handler(**MAILERRORS,flood_level=flood_level) | 
        
          |  | mail_handler.setLevel(level) | 
        
          |  | logger.addHandler(mail_handler) | 
        
          |  | 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 | 
        
          |  | ''')) | 
        
          |  |  | 
        
          |  |  | 
        
          |  |  | 
        
          |  |  | 
        
          |  | def test() : | 
        
          |  | logger=logging.getLogger() | 
        
          |  | from credentials import MAILERRORS | 
        
          |  | send_email_on(logger,level=logging.ERROR,flood_level=1) | 
        
          |  | print("Look out. Error below should be arriving at {toaddrs} from {fromaddr}".format(**MAILERRORS)) | 
        
          |  | try : | 
        
          |  | 1/0 | 
        
          |  | except Exception as e: | 
        
          |  | logger.exception(e) | 
        
          |  | print("next one should result in a flood warning") | 
        
          |  | try : | 
        
          |  | 1/0 | 
        
          |  | except Exception as e: | 
        
          |  | logger.exception(e) | 
        
          |  |  | 
        
          |  |  | 
        
          |  |  | 
        
          |  |  | 
        
          |  | if __name__ == '__main__' : | 
        
          |  | test() | 
        
          |  |  | 
        
          |  |  | 
        
          |  |  | 
        
          |  |  |