Email Logging

Red Mail also provides logging handlers which extends the logging library’s handlers from the standard library. The logging library also has SMTPHandler but its features are somewhat restricted. It does only send a logging message formatted as plain text and it sends only one log record per email.

Red Mail’s email handlers, on the other hand, are capable of formatting the emails in arbitrary ways and it also enables to send multiple log records with one email. Red Mail is more feature complete and provides more customizable logging experience.

There are two log handlers provided by Red Mail:

The mechanics are simple and very similar between these two handlers.

EmailHandler

To send one log record per email, use EmailHandler:

import logging
from redmail import EmailHandler

hdlr = EmailHandler(
    host="localhost",
    port=0,
    subject="A log record",
    sender="no-reply@example.com",
    receivers=["me@example.com"],
)
logger = logging.getLogger(__name__)
logger.addHandler(hdlr)

# To use:
logger.warning("A warning happened")

Note

You may pass the EmailSender directly as an argument email, for example:

from redmail import EmailSender
hdlr = EmailHandler(
    email=EmailSender(host="localhost", port=0)
    subject="A log record",
    receivers=["me@example.com"],
)

Note that a copy of the EmailSender is created in order to avoid affecting the usage of the instance elsewhere. Additional arguments (such as subject, sender, receivers, text, html, etc.) are set as attributes to this copied instance.

You may also template the subject and the bodies:

import logging
from redmail import EmailHandler

hdlr = EmailHandler(
    host="localhost",
    port=0,
    subject="Log Record: {record.levelname}",
    receivers=["me@example.com"],
    text="Logging level: {{ record.levelname }}\nMessage: {{ msg }}",
    html="<ul><li>Logging level: {{ record.levelname }}</li><li>Message: {{ msg }}</li></ul>",
)
logger = logging.getLogger(__name__)
logger.addHandler(hdlr)

As you may have noted, the subject can contain string formatting. The following arguments are passed to the string format:

Argument

Type

Description

record

logging.LogRecord

Log records to send

handler

EmailHandler

EmailHandler itself

In addition, the text and HTML bodies are processed using Jinja and the following parameters are passed:

Argument

Type

Description

record

logging.LogRecord

Log record

msg

str

Formatted message

handler

EmailHandler

EmailHandler itself

MultiEmailHandler

To send multiple log records with one email, use MultiEmailHandler:

import logging
from redmail import MultiEmailHandler

hdlr = MultiEmailHandler(
    capacity=2, # Sends email after every second record
    host="localhost",
    port=0,
    subject="log records",
    sender="no-reply@example.com",
    receivers=["me@example.com"],
)
logger = logging.getLogger(__name__)
logger.addHandler(hdlr)

# To use:
logger.warning("A warning happened")
logger.warning("Another warning happened")
# (Now an email should have been sent)

# You may also manually flush
logger.warning("A warning happened")
hdlr.flush()

Note

You may pass the EmailSender directly as an argument email, for example:

from redmail import EmailSender
hdlr = MultiEmailHandler(
    email=EmailSender(host="localhost", port=0)
    subject="Log records",
    receivers=["me@example.com"],
)

Note that a copy of the EmailSender is created in order to avoid affecting the usage of the instance elsewhere. Additional arguments (such as subject, sender, receivers, text, html, etc.) are set as attributes to this copied instance.

You may also template the subject and the bodies:

import logging
from redmail import EmailHandler

hdlr = MultiEmailHandler(
    host="localhost",
    port=0,
    subject="Log Records: {min_level_name} - {max_level_name}",
    receivers=["me@example.com"],
    text="""Logging level:
        {% for record in records %}
        Level name: {{ record.levelname }}
        Message: {{ record.msg }}
        {% endfor %}
    """,
    html="""
        <ul>
        {% for record in records %}
            <li>Logging level: {{ record.levelname }}</li>
            <li>Message: {{ record.msg }}</li>
        {% endfor %}
        </ul>
    """,
)
logger = logging.getLogger(__name__)
logger.addHandler(hdlr)

As you may have noted, the subject can contain string formatting. The following arguments are passed to the string format:

Argument

Type

Description

records

list of logging.LogRecord

Log records to send

min_level_name

str

Name of the lowest log level name

max_level_name

str

Name of the highest log level name

handler

MultiEmailHandler

MultiEmailHandler itself

In addition, the text and HTML bodies are processed using Jinja and the following parameters are passed:

Argument

Type

Description

records

list of logging.LogRecord

List of log records

msgs

list of str

List of formatted messages

handler

MultiEmailHandler

MultiEmailHandler itself