Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support message log without message data #176

Merged
merged 4 commits into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,13 @@ that the message will be retried indefinitely. If you set this to a value of ``0
the message will not be retried at all, any number greater than ``0`` will be the
maximum number of retries (excluding the initial attempt).

To not log the email contents after sending it, you can set ``MAILER_EMAIL_LOG_MESSAGE_DATA``
to `False`. The default is ``True``, which means that the message will be stored with the full
email content. If you set this to the value ``False``, only the message meta data and result
status will be stored in the ``MessageLog`` table.
Disabling storing the email content can be useful for privacy or performance reasons,
it also helps to not increase the database size.

Using the DontSendEntry table
=============================

Expand Down
17 changes: 15 additions & 2 deletions src/mailer/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,25 @@


def show_to(message):
return ", ".join(message.to_addresses)
if message.email:
return ", ".join(message.to_addresses)
else:
return "<Message data unavailable>"


show_to.short_description = "To" # noqa: E305


def show_subject(message):
if message.email:
return message.subject
else:
return "<Message data unavailable>"


show_subject.short_description = "Subject" # noqa: E305


class MessageAdminMixin:
def plain_text_body(self, instance):
email = instance.email
Expand Down Expand Up @@ -40,7 +53,7 @@ class DontSendEntryAdmin(admin.ModelAdmin):

class MessageLogAdmin(MessageAdminMixin, admin.ModelAdmin):

list_display = ["id", show_to, "subject", "message_id", "when_attempted", "result"]
list_display = ["id", show_to, show_subject, "message_id", "when_attempted", "result"]
list_filter = ["result"]
date_hierarchy = "when_attempted"
readonly_fields = ["plain_text_body", "message_id"]
Expand Down
18 changes: 18 additions & 0 deletions src/mailer/migrations/0007_alter_messagelog_message_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.0.4 on 2024-04-13 09:37

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("mailer", "0006_message_retry_count"),
]

operations = [
migrations.AlterField(
model_name="messagelog",
name="message_data",
field=models.TextField(null=True),
),
]
16 changes: 11 additions & 5 deletions src/mailer/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,11 @@ def log(self, message, result_code, log_message=""):
create a log entry for an attempt to send the given message and
record the given result and (optionally) a log message
"""
log_message_data = getattr(settings, "MAILER_EMAIL_LOG_MESSAGE_DATA", True)
message_data = message.message_data if log_message_data else None

return self.create(
message_data=message.message_data,
message_data=message_data,
message_id=get_message_id(message.email),
when_added=message.when_added,
priority=message.priority,
Expand All @@ -271,7 +274,7 @@ class MessageLog(BigAutoModel):
"""

# fields from Message
message_data = models.TextField()
message_data = models.TextField(null=True)
message_id = models.TextField(editable=False, null=True)
when_added = models.DateTimeField(db_index=True)
priority = models.PositiveSmallIntegerField(choices=PRIORITIES, db_index=True)
Expand All @@ -290,7 +293,10 @@ class Meta:
def __str__(self):
try:
email = self.email
return f"On {self.when_attempted}, \"{email.subject}\" to {', '.join(email.to)}"
if email:
return f"On {self.when_attempted}, \"{email.subject}\" to {', '.join(email.to)}"
else:
return f'On {self.when_attempted}, "{self.message_id}"'
except Exception:
return "<MessageLog repr unavailable>"

Expand All @@ -304,12 +310,12 @@ def to_addresses(self):
if email is not None:
return email.to
else:
return []
return None

@property
def subject(self):
email = self.email
if email is not None:
return email.subject
else:
return ""
return None
38 changes: 34 additions & 4 deletions tests/test_mailer.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import datetime
import pickle
import time
from unittest.mock import Mock, patch
from unittest.mock import Mock, PropertyMock, patch

import django
import lockfile
Expand Down Expand Up @@ -634,8 +634,34 @@ def test_message_log(self):
# Fake a log entry without email
log.message_data = ""

self.assertEqual(log.to_addresses, [])
self.assertEqual(log.subject, "")
self.assertEqual(log.to_addresses, None)
self.assertEqual(log.subject, None)

def test_message_log_without_log_message_data(self):
with self.settings(
MAILER_EMAIL_BACKEND="django.core.mail.backends.locmem.EmailBackend",
MAILER_EMAIL_LOG_MESSAGE_DATA=False,
): # noqa
mailer.send_mail("Subject Log", "Body", "log1@example.com", ["1gol@example.com"])

self.assertEqual(Message.objects.count(), 1)
self.assertEqual(Message.objects.deferred().count(), 0)
self.assertEqual(MessageLog.objects.count(), 0)
when_added = Message.objects.first().when_added

engine.send_all()

self.assertEqual(Message.objects.count(), 0)
self.assertEqual(Message.objects.deferred().count(), 0)
self.assertEqual(MessageLog.objects.count(), 1)

log = MessageLog.objects.all()[0]

self.assertEqual(log.email, None)
self.assertEqual(log.message_data, None)
self.assertEqual(log.to_addresses, None)
self.assertEqual(log.subject, None)
self.assertEqual(log.when_added, when_added)

def test_message_str(self):
with self.settings(MAILER_EMAIL_BACKEND="django.core.mail.backends.locmem.EmailBackend"):
Expand Down Expand Up @@ -664,8 +690,12 @@ def test_message_log_str(self):
f'On {log.when_attempted}, "Subject Log 中" to 1gol@example.com',
)

with patch.object(MessageLog, "when_attempted", new_callable=PropertyMock) as log_mock:
log_mock.side_effect = ValueError
self.assertEqual(str(log), "<MessageLog repr unavailable>")

log.message_data = None
self.assertEqual(str(log), "<MessageLog repr unavailable>")
self.assertEqual(str(log), f'On {log.when_attempted}, "{log.message_id}"')


class DbToEmailTest(TestCase):
Expand Down
Loading