1

The question has already appeared on the site: Collate output in Python logging MemoryHandler with SMTPHandler

It was added 9 years ago and concerns the old version of python.

SMTPHandler sends each email with logging.info ('msg') separately

This is for The SMTPHandler class, located in the logging.handlers module logging.info(), located in the logging module smtplib.SMTP_SSL or smtplib.SMTP, located in the smtplib module


import logging
from logging.handlers import SMTPHandler
import smtplib

smtp = smtplib.SMTP_SSL('host', 465)
smtp.ehlo()
smtp.login('login', 'password')
mail_handler = SMTPHandler(mailhost='host', fromaddr='email', toaddrs=['email'], subject='Msg', credentials=('login','password'), secure=())
logging.basicConfig(handlers=[mail_handler], level=logging.INFO, format='%(asctime)s - %(message)s')

logging.info('msg')

smtp.quit()

I would like to get one email with all logging.info messages from time to time

Nelio
  • 11
  • 1

1 Answers1

0

This is an old question but I'm leaving an answer here in case anyone shows up like me.

The answer is given here and I modified it for TLS usage.

import logging
import logging.handlers as handlers

#mail sender informations
mail_host     = 'smtp-legacy.office365.com'
mail_port     = 587
mail_from     = 'email_address@g.com'
mail_password = 'password'
mail_to       = ['receiver_1','receiver_2'] #seperate it with comma for other addresses
mail_subject  = 'Test Logging email from Python logging module (buffering)'

#Setting up a buffered email logger class to send emails as bulk. capacity variable defines the bulk size
class BufferingSMTPHandler(logging.handlers.BufferingHandler):
    def __init__(self, mailhost, mailport, fromaddr, mailpwd, toaddrs, subject, capacity):
        logging.handlers.BufferingHandler.__init__(self, capacity)
        self.mailhost = mailhost
        self.mailport = mailport
        self.fromaddr = fromaddr
        self.toaddrs = toaddrs
        self.subject = subject
        self.password = mailpwd
        self.setFormatter(formatter)

        
    #this is called by the smtphandler of the logging itself, below is just the setup of the mail and sending it
    def flush(self):
        if len(self.buffer) > 0:
            try:
                import smtplib, ssl
                port = self.mailport
                if not port:
                    port = smtplib.SMTP_PORT
                context = ssl.create_default_context()
                smtp = smtplib.SMTP(self.mailhost, port)
                smtp.starttls(context=context)
                msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n" % (self.fromaddr, ','.join(self.toaddrs), self.subject)
                for record in self.buffer:
                    s = self.format(record)
                    print (s)
                    msg = msg + s + "\r\n"
                smtp.login(self.fromaddr, self.password)
                smtp.sendmail(self.fromaddr, self.toaddrs, msg)
                smtp.quit()
            except:
                self.handleError(None)  # no particular record
            self.buffer = []
    

Usage is like below

#logging obj creation and set a level to keep in the server main log file.
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

logMailHandler = BufferingSMTPHandler(mail_host, mail_port, mail_from, mail_password, mail_to, mail_subject, 2)
logger.addHandler(logMailHandler)

logger.critical('My critical error')
logger.critical('My critical error2') # in the second call it'll send the email
Taylan Yuksel
  • 345
  • 3
  • 12