Skip to content

Commit

Permalink
Merge pull request #5907 from nyaruka/email-subject-templates
Browse files Browse the repository at this point in the history
Allow template-based email subjects
  • Loading branch information
rowanseymour authored Feb 26, 2025
2 parents 5e6c1be + 0e466ba commit ee87c31
Show file tree
Hide file tree
Showing 6 changed files with 25 additions and 10 deletions.
2 changes: 1 addition & 1 deletion temba/notifications/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ def send_email(self):

if subject and template:
sender = EmailSender.from_email_type(self.org.branding, "notifications")
sender.send([self.email_address or self.user.email], f"[{self.org.name}] {subject}", template, context)
sender.send([self.email_address or self.user.email], template, context, f"[{self.org.name}] {subject}")
else: # pragma: no cover
logger.error(f"pending emails for notification type {self.type.slug} not configured for email")

Expand Down
7 changes: 5 additions & 2 deletions temba/orgs/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1333,9 +1333,12 @@ def send(self):
sender = EmailSender.from_email_type(self.org.branding, "notifications")
sender.send(
[self.email],
_("%(name)s Invitation") % self.org.branding,
"orgs/email/invitation_email",
{"org": self.org, "invitation": self},
{
"org": self.org,
"invitation": self,
},
_("%(name)s Invitation") % self.org.branding,
)

def accept(self, user):
Expand Down
7 changes: 5 additions & 2 deletions temba/orgs/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,12 @@ def send_user_verification_email(org_id, user_id):
sender = EmailSender.from_email_type(org.branding, "notifications")
sender.send(
[user.email],
_("%(name)s Email Verification") % org.branding,
"orgs/email/email_verification",
{"org": org, "secret": user.email_verification_secret},
{
"org": org,
"secret": user.email_verification_secret,
},
_("%(name)s Email Verification") % org.branding,
)

r.set(key, "1", ex=60 * 10)
Expand Down
2 changes: 1 addition & 1 deletion temba/orgs/views/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def clean(self):
recipients = [admin.email for admin in self.org.get_admins().order_by("email")]
subject = _("%(name)s SMTP settings test") % self.org.branding
try:
sender.send(recipients, subject, "orgs/email/smtp_test", {})
sender.send(recipients, "orgs/email/smtp_test", {}, subject)
except smtplib.SMTPException as e:
raise ValidationError(_("SMTP settings test failed with error: %s") % str(e))
except Exception:
Expand Down
7 changes: 5 additions & 2 deletions temba/orgs/views/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -602,9 +602,12 @@ def form_valid(self, form):
sender = EmailSender.from_email_type(self.request.branding, "notifications")
sender.send(
[user.email],
_("Password Recovery Request"),
"orgs/email/user_forget",
{"user": user, "path": reverse("orgs.user_recover", args=[token.token])},
{
"user": user,
"path": reverse("orgs.user_recover", args=[token.token]),
},
_("Password Recovery Request"),
)
else:
# no user, check if we have an invite for the email and resend that
Expand Down
10 changes: 8 additions & 2 deletions temba/utils/email/send.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,21 @@ def from_smtp_url(cls, branding: dict, smtp_url: str):

return cls(branding, connection, from_email)

def send(self, recipients: list, subject: str, template: str, context: dict):
def send(self, recipients: list, template: str, context: dict, subject: str = None):
"""
Sends a multi-part email rendered from templates for the text and html parts. `template` should be the name of
the template, without .html or .txt (e.g. 'channels/email/power_charging').
"""
html_template = loader.get_template(template + ".html")
text_template = loader.get_template(template + ".txt")

context["subject"] = subject
if not subject: # pragma: no cover
try:
subject_template = loader.get_template(template + "_subject.txt")
subject = subject_template.render(context)
except loader.TemplateDoesNotExist:
raise ValueError("No subject provided and subject template doesn't exist")

context["branding"] = self.branding
context["now"] = timezone.now()

Expand Down

0 comments on commit ee87c31

Please sign in to comment.