title: Send E-Mail with output log and success status in Python
body: <p>I want to send an E-Mail automatically after each script run, whether it was successfull or not.
  The E-Mail should include logs and in case of an error the stack trace.
  The subject should contain a postfix that tells whether there the run was with errors (&quot;ERROR&quot;) or without errors (&quot;SUCCESS&quot;).</p>
  <p>Currently I'm using using the follwing code, which does this in an ugly way:</p>
  <pre><code>if __name__ == '__main__':
      # setup logging and e-mail messaging
      logger = logging.getLogger(__name__)  # Creating an instance of logger
      logger.setLevel(logging.DEBUG)
      mail_handler = BufferingSMTPHandler(fromaddr='xyz@test.de',
                                          toaddr=['xyz@tzest.de'],
                                          subject='JOB: Testjob')
      mail_handler.setLevel(logging.INFO)  # Set minimum level to receive messages
      logger.addHandler(mail_handler)
      # rest of __main__ is at the end of the file!
  
  
  def handle_exception(exc_type, exc_value, exc_traceback):
      if issubclass(exc_type, KeyboardInterrupt):
          sys.__excepthook__(exc_type, exc_value, exc_traceback)
          return
  
      logger.critical(&quot;Uncaught exception&quot;, exc_info=(exc_type, exc_value, exc_traceback))
      mail_handler.set_failed(True)
      mail_handler.flush()
  
  if __name__ == '__main__':
      .... do work here
      logger.info('TEST')
      ....
      mail_handler.set_failed(False)  # reached end of the script, so success is assumed
      mail_handler.flush()
  </code></pre>
  <p>The BufferingSMTPHandler looks like this:</p>
  <pre><code>import logging
  import logging.handlers
  import smtplib
  
  
  class BufferingSMTPHandler(logging.handlers.BufferingHandler):
      def __init__(self, subject, fromaddr, toaddr, mailhost='mysmtpserver', capacity=500):
          logging.handlers.BufferingHandler.__init__(self, capacity)
          self.mailhost = mailhost
          self.fromaddr = fromaddr
          self.toaddr = toaddr
          self.subject = subject
          self.failed = False
  
          self.setFormatter(logging.Formatter(
              '{levelname} - {asctime} - {lineno} - {name} -  In {funcName}: {message}',
              style='{'))  # Formatter to prettify logs
  
      def set_failed(self, failed):
          self.failed = failed
  
      def flush(self):  # Method to send emails
          if len(self.buffer) &lt;= 0:
              return
  
          with smtplib.SMTP(self.mailhost) as smtp:
              if self.failed:
                  subject = self.subject + ' - ERROR'
              else:
                  subject = self.subject + ' - SUCCESS'
              body = ''
  
              for record in self.buffer:
                  body += self.format(record) + '\n'  # Populating body of the message with formatted logs
  
              msg = f'Subject: {subject}\n\n{body}'
  
              smtp.sendmail(self.fromaddr, self.toaddr, msg)
              self.buffer.clear()  # Clearing buffer to allude sending same logs
  </code></pre>
  <p>Is there a way to do this without adding so much code to the main script?</p>
  <p>E.g. in this kind of way (pseudo-code):</p>
  <pre><code>from status_mailer import AutoStatusMailer
  
  if __name__ == '__main__':
    mailer = AutoStatusMailer(fromaddr='xyz@test.de', toaddr=['xyz@tzest.de'], subject='JOB: Testjob')
    logger = mailer.get_logger()
    .... do work here
    logger.info('TEST')
    ...
    ... status mail is automatically sent afterwards
  </code></pre>