Skip to content

Commit 92967b1

Browse files
committed
Store sent emails in S3
1 parent 89c8b0d commit 92967b1

File tree

6 files changed

+67
-12
lines changed

6 files changed

+67
-12
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Generated by Django 5.1.4 on 2025-03-09 22:29
2+
3+
import notifications.models
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('notifications', '0021_alter_emailtemplate_identifier'),
11+
]
12+
13+
operations = [
14+
migrations.AddField(
15+
model_name='sentemail',
16+
name='body_file',
17+
field=models.FileField(blank=True, null=True, upload_to=notifications.models.sent_email_body_upload_to, verbose_name='body file'),
18+
),
19+
migrations.AddField(
20+
model_name='sentemail',
21+
name='text_body_file',
22+
field=models.FileField(blank=True, null=True, upload_to=notifications.models.sent_email_body_upload_to, verbose_name='text body file'),
23+
),
24+
]

backend/notifications/models.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from model_utils.models import TimeStampedModel
99
from django.utils.translation import gettext_lazy as _
1010
from django.conf import settings
11+
from django.core.files.base import ContentFile
1112

1213
BASE_PLACEHOLDERS = ["conference"]
1314

@@ -253,12 +254,20 @@ def send_email(
253254
placeholders=placeholders,
254255
subject=processed_email_template.subject,
255256
preview_text=processed_email_template.preview_text,
256-
body=processed_email_template.html_body,
257-
text_body=processed_email_template.text_body,
257+
body="",
258+
text_body="",
258259
reply_to=self.reply_to,
259260
cc_addresses=self.cc_addresses,
260261
bcc_addresses=self.bcc_addresses,
261262
)
263+
sent_email.body_file.save(
264+
"body.html",
265+
ContentFile(processed_email_template.html_body.encode("utf-8")),
266+
)
267+
sent_email.text_body_file.save(
268+
"text_body.txt",
269+
ContentFile(processed_email_template.text_body.encode("utf-8")),
270+
)
262271

263272
transaction.on_commit(lambda: send_pending_email.delay(sent_email.id))
264273

@@ -290,6 +299,10 @@ class Meta:
290299
]
291300

292301

302+
def sent_email_body_upload_to(instance, filename):
303+
return f"sent_emails/{instance.id}/{filename}"
304+
305+
293306
class SentEmail(TimeStampedModel):
294307
class Status(models.TextChoices):
295308
pending = "pending", _("Pending")
@@ -333,7 +346,13 @@ class Status(models.TextChoices):
333346

334347
subject = models.TextField(_("subject"))
335348
body = models.TextField(_("body"))
349+
body_file = models.FileField(
350+
_("body file"), upload_to=sent_email_body_upload_to, blank=True, null=True
351+
)
336352
text_body = models.TextField(_("text body"))
353+
text_body_file = models.FileField(
354+
_("text body file"), upload_to=sent_email_body_upload_to, blank=True, null=True
355+
)
337356
preview_text = models.TextField(_("preview text"), blank=True)
338357

339358
from_email = models.EmailField(_("from email"))

backend/notifications/tasks.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,26 @@ def send_pending_email(self, sent_email_id: int):
6363
def send_email(sent_email, email_backend_connection):
6464
logger.info(f"Sending sent_email_id={sent_email.id}")
6565

66+
if sent_email.body_file:
67+
html_body = sent_email.body_file.read().decode("utf-8")
68+
else:
69+
html_body = sent_email.body
70+
71+
if sent_email.text_body_file:
72+
text_body = sent_email.text_body_file.read().decode("utf-8")
73+
else:
74+
text_body = sent_email.text_body
75+
6676
email_message = EmailMultiAlternatives(
6777
subject=sent_email.subject,
68-
body=sent_email.text_body,
78+
body=text_body,
6979
from_email=sent_email.from_email,
7080
to=[sent_email.recipient_email],
7181
cc=sent_email.cc_addresses,
7282
bcc=sent_email.bcc_addresses,
7383
reply_to=[sent_email.reply_to],
7484
connection=email_backend_connection,
7585
)
76-
email_message.attach_alternative(sent_email.body, "text/html")
86+
email_message.attach_alternative(html_body, "text/html")
7787
email_message.send()
7888
return email_message.extra_headers.get("message_id", f"local-{uuid4()}")

backend/notifications/tests/test_models.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ def test_send_email_template_to_recipient_email(
7474
assert sent_email.recipient_email == "[email protected]"
7575

7676
assert sent_email.subject == "Subject abc"
77-
assert "Body abc" in sent_email.body
77+
assert "Body abc" in sent_email.body_file.read().decode("utf-8")
7878
assert sent_email.preview_text == "Preview abc"
7979
assert sent_email.reply_to == "[email protected]"
8080

@@ -102,7 +102,8 @@ def test_send_email_template_to_recipient_user():
102102
assert sent_email.recipient_email == user.email
103103

104104
assert sent_email.subject == "Subject abc"
105-
assert "Body abc" in sent_email.body
105+
assert "Body abc" in sent_email.body_file.read().decode("utf-8")
106+
assert "Body abc" in sent_email.text_body_file.read().decode("utf-8")
106107
assert sent_email.preview_text == "Preview abc"
107108
assert sent_email.reply_to == "[email protected]"
108109

@@ -137,7 +138,7 @@ def test_send_system_template_email(settings):
137138
assert sent_email.from_email == "[email protected]"
138139

139140
assert sent_email.subject == "Subject abc"
140-
assert "Body abc" in sent_email.body
141+
assert "Body abc" in sent_email.body_file.read().decode("utf-8")
141142
assert sent_email.preview_text == "Preview abc"
142143
assert sent_email.reply_to == "[email protected]"
143144

backend/pycon/storages.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66
from django.core.files.storage.memory import InMemoryStorage
77
from django.core.files.storage import FileSystemStorage
88
from django.urls import reverse
9+
from django.core.files.storage import storages
10+
11+
12+
def private_storage_getter():
13+
return storages["private"]
914

1015

1116
@dataclass

backend/visa/models.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from functools import cached_property
22
from django.db import transaction
33

4+
from pycon.storages import private_storage_getter
45
from submissions.models import Submission
56
from users.models import User
67
from grants.models import Grant
@@ -10,7 +11,6 @@
1011
from django.db import models
1112
from django.db.models import UniqueConstraint, Q
1213
from django.utils.translation import gettext_lazy as _
13-
from django.core.files.storage import storages
1414

1515

1616
class InvitationLetterRequestStatus(models.TextChoices):
@@ -31,10 +31,6 @@ def invitation_letter_upload_to(instance, filename):
3131
return f"invitation_letters/{instance.conference.code}/{instance.id}/{filename}"
3232

3333

34-
def private_storage_getter():
35-
return storages["private"]
36-
37-
3834
class InvitationLetterRequest(TimeStampedModel):
3935
objects = InvitationLetterRequestQuerySet().as_manager()
4036

0 commit comments

Comments
 (0)