From 88e195d003b75f9ed3d2e2debc6f62457aa978d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrico=20Tr=C3=B6ger?= Date: Sat, 13 Apr 2024 12:06:31 +0200 Subject: [PATCH 1/4] Add setting "MAILER_EMAIL_LOG_MESSAGE_DATA" to disable data logging This setting allows to not storing the full email contents in the message log. This helps to reduce the size of database and might be good for privacy reasons. --- docs/usage.rst | 7 +++++ src/mailer/admin.py | 19 ++++++++++++-- .../0007_alter_messagelog_message_data.py | 18 +++++++++++++ src/mailer/models.py | 7 +++-- tests/test_mailer.py | 26 +++++++++++++++++++ 5 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 src/mailer/migrations/0007_alter_messagelog_message_data.py diff --git a/docs/usage.rst b/docs/usage.rst index 9779010..5111233 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -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 ============================= diff --git a/src/mailer/admin.py b/src/mailer/admin.py index dc30fdb..ef2dae3 100644 --- a/src/mailer/admin.py +++ b/src/mailer/admin.py @@ -6,12 +6,27 @@ def show_to(message): - return ", ".join(message.to_addresses) + to_addresses = message.to_addresses + if to_addresses: + return ", ".join(message.to_addresses) + else: + return "" show_to.short_description = "To" # noqa: E305 +def show_subject(message): + subject = message.subject + if subject: + return subject + else: + return "" + + +show_subject.short_description = "Subject" # noqa: E305 + + class MessageAdminMixin: def plain_text_body(self, instance): email = instance.email @@ -40,7 +55,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"] diff --git a/src/mailer/migrations/0007_alter_messagelog_message_data.py b/src/mailer/migrations/0007_alter_messagelog_message_data.py new file mode 100644 index 0000000..489084e --- /dev/null +++ b/src/mailer/migrations/0007_alter_messagelog_message_data.py @@ -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), + ), + ] diff --git a/src/mailer/models.py b/src/mailer/models.py index 3374919..6bcef1f 100644 --- a/src/mailer/models.py +++ b/src/mailer/models.py @@ -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, @@ -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) diff --git a/tests/test_mailer.py b/tests/test_mailer.py index 95e2373..e6fd272 100644 --- a/tests/test_mailer.py +++ b/tests/test_mailer.py @@ -637,6 +637,32 @@ def test_message_log(self): self.assertEqual(log.to_addresses, []) self.assertEqual(log.subject, "") + 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, []) + self.assertEqual(log.subject, "") + self.assertEqual(log.when_added, when_added) + def test_message_str(self): with self.settings(MAILER_EMAIL_BACKEND="django.core.mail.backends.locmem.EmailBackend"): mailer.send_mail("Subject Msg 中", "Body 中", "msg1@example.com", ["rec1@example.com"]) From 59b874f802b01628cc190137e3ab83ad0352dce3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrico=20Tr=C3=B6ger?= Date: Sat, 13 Apr 2024 12:07:29 +0200 Subject: [PATCH 2/4] Improve repesentation of MessageLog is no message data is available --- src/mailer/models.py | 5 ++++- tests/test_mailer.py | 8 ++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/mailer/models.py b/src/mailer/models.py index 6bcef1f..73b3ca3 100644 --- a/src/mailer/models.py +++ b/src/mailer/models.py @@ -293,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 "" diff --git a/tests/test_mailer.py b/tests/test_mailer.py index e6fd272..e846648 100644 --- a/tests/test_mailer.py +++ b/tests/test_mailer.py @@ -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 @@ -690,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), "") + log.message_data = None - self.assertEqual(str(log), "") + self.assertEqual(str(log), f'On {log.when_attempted}, "{log.message_id}"') class DbToEmailTest(TestCase): From c3361ada344e5e0b2c0102eea7ce5505291978bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrico=20Tr=C3=B6ger?= Date: Sat, 13 Apr 2024 18:45:35 +0200 Subject: [PATCH 3/4] fixup: improve message list in django-admin --- src/mailer/admin.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/mailer/admin.py b/src/mailer/admin.py index ef2dae3..db7ed04 100644 --- a/src/mailer/admin.py +++ b/src/mailer/admin.py @@ -6,22 +6,20 @@ def show_to(message): - to_addresses = message.to_addresses - if to_addresses: + if message.email: return ", ".join(message.to_addresses) else: - return "" + return "" show_to.short_description = "To" # noqa: E305 def show_subject(message): - subject = message.subject - if subject: - return subject + if message.email: + return message.subject else: - return "" + return "" show_subject.short_description = "Subject" # noqa: E305 From 799122345e0ab37341561ebaa2e8115995f9b8d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrico=20Tr=C3=B6ger?= Date: Sat, 13 Apr 2024 18:46:09 +0200 Subject: [PATCH 4/4] fixup: If no message data is available, make subject and to_addresses return None --- src/mailer/models.py | 4 ++-- tests/test_mailer.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mailer/models.py b/src/mailer/models.py index 73b3ca3..3514483 100644 --- a/src/mailer/models.py +++ b/src/mailer/models.py @@ -310,7 +310,7 @@ def to_addresses(self): if email is not None: return email.to else: - return [] + return None @property def subject(self): @@ -318,4 +318,4 @@ def subject(self): if email is not None: return email.subject else: - return "" + return None diff --git a/tests/test_mailer.py b/tests/test_mailer.py index e846648..d6763c6 100644 --- a/tests/test_mailer.py +++ b/tests/test_mailer.py @@ -634,8 +634,8 @@ 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( @@ -659,8 +659,8 @@ def test_message_log_without_log_message_data(self): self.assertEqual(log.email, None) self.assertEqual(log.message_data, None) - self.assertEqual(log.to_addresses, []) - self.assertEqual(log.subject, "") + self.assertEqual(log.to_addresses, None) + self.assertEqual(log.subject, None) self.assertEqual(log.when_added, when_added) def test_message_str(self):