How can I log all outgoing email in Django?
Asked Answered
I

4

14

My Django application sends out quite a bit of emails and I've tried testing it thoroughly. However, for the first few months, I'd like to log all outgoing emails to ensure that everything is working smoothly.

Is there a Django module that allows me to do this and makes the outgoing emails visible through the administration panel?

Improvisator answered 26/9, 2011 at 8:11 Comment(0)
I
11

I wrote a custom email backend which logs the stuff to a model.

Here's my backend:

from django.core.mail.backends.smtp import *
from django.db import transaction

from modules.common.models import *

class LoggingEmailBackend(EmailBackend):
    """
    A wrapper around the SMTP backend that logs all emails to the DB.
    """
    def send_messages(self, email_messages):
    """
    A helper method that does the actual logging
    """
    with transaction.commit_on_success():

        for email_message in email_messages:

            email_record = Email.objects.create(
                to='; '.join(email_message.recipients()),
                subject=email_message.subject, body=email_message.body,
            )

            try:
                return super(LoggingEmailBackend, self)._send(
                    email_message
                )
            except:
                email_record.ok = False
                return False
            finally:
                email_record.ok = True
                return True

Here's the model:

class Email(models.Model):
    """
    Model to store all the outgoing emails.
    """
    when = models.DateTimeField(
        null=False, auto_now_add=True
    )
    to = models.EmailField(
        null=False, blank=False,
    )
    subject = models.CharField(
         null=False, max_length=128,
    )
    body = models.TextField(
        null=False, max_length=1024,
    )
    ok = models.BooleanField(
        null=False, default=True,
    )

Here's my model:

from django.contrib import admin

from modules.common.models import *

class EmailAdmin(admin.ModelAdmin):
    """
    Admin part for managing the the Email model
    """
    list_display = ['to', 'subject', 'ok',]
    list_filter = ['ok']
    readonly_fields = ['when', 'to', 'subject', 'body', 'ok']
    search_fields = ['subject', 'body', 'to']

    def has_delete_permission(self, request, obj=None):
        return False

    def has_add_permission(self, request):
        return False


admin.site.register(Email, EmailAdmin)
Improvisator answered 26/9, 2011 at 10:30 Comment(1)
This will not record ok = False on failure. The model is not saved.Endocrinology
M
10

Since the OP asked about logging and not about saving to DB, here's a middleware that does that:

import django.core.mail.backends.smtp
import logging

logger = logging.getLogger(__name__)  # or you could enter a specific logger name

class LoggingBackend(django.core.mail.backends.smtp.EmailBackend):

  def send_messages(self, email_messages):
    try:
        for msg in email_messages:
            logger.info(u"Sending message '%s' to recipients: %s", msg.subject, msg.to)
    except:
        logger.exception("Problem logging recipients, ignoring")

    return super(LoggingBackend, self).send_messages(email_messages)

and then in your settings.py:

EMAIL_BACKEND = 'whereiputit.LoggingBackend'
Mosher answered 7/6, 2016 at 15:8 Comment(2)
Hey do you have an idea if this would not work in celery? It seems to have trouble to be imported for meHood
@Hood in principle, no reason it shouldn't work in celery.Mosher
C
2

I do not know if there exists a module that works this way, but writing a custom one is a piece of cake. Just create a separate model and every time you send an email, create a new instance ( use a custom method for email sending ). Then, link this model with the admin and bingo..

Chaschase answered 26/9, 2011 at 8:24 Comment(0)
O
2

Django offers custom E-Mail backends, you can write one on your own.

Organdy answered 26/9, 2011 at 9:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.