Redesign claim-approved and password-reset emails as branded HTML
Confirmed Resend's /emails endpoint accepts an html field alongside text. Claim-approved email now carries an HTML alternative with the club's logo/colours; allauth's password-reset email is overridden with the same treatment, falling back to RosterChief's own branding outside a club context. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -16,7 +16,7 @@ from allauth.account.forms import default_token_generator
|
||||
from allauth.account.utils import user_pk_to_url_str
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.mail import send_mail
|
||||
from django.core.mail import EmailMultiAlternatives
|
||||
from django.db import transaction
|
||||
from django.db.models import Exists, OuterRef, Q
|
||||
from django.template.loader import render_to_string
|
||||
@@ -170,12 +170,20 @@ def send_claim_approved_email(claim, *, child, request=None):
|
||||
path = reverse("account_reset_password_from_key", kwargs={"uidb36": user_pk_to_url_str(user), "key": default_token_generator.make_token(user)})
|
||||
set_password_url = request.build_absolute_uri(path) if request is not None else path
|
||||
|
||||
context = {"club": claim.club, "child": child, "parent_first_name": claim.parent_first_name, "set_password_url": set_password_url}
|
||||
# "request" rides along in the context (not used by the .txt template, only
|
||||
# by the .html one's {% absolute_media_url %} tag) so the club's logo -- if
|
||||
# it has one -- renders as an absolute URL an inbox can actually fetch, the
|
||||
# same way set_password_url above is made absolute.
|
||||
context = {"club": claim.club, "child": child, "parent_first_name": claim.parent_first_name, "set_password_url": set_password_url, "request": request}
|
||||
subject = " ".join(render_to_string("members/email/claim_approved_subject.txt", context).split())
|
||||
body = render_to_string("members/email/claim_approved.txt", context).strip() + "\n"
|
||||
text_body = render_to_string("members/email/claim_approved.txt", context).strip() + "\n"
|
||||
html_body = render_to_string("members/email/claim_approved.html", context)
|
||||
|
||||
message = EmailMultiAlternatives(subject, text_body, settings.DEFAULT_FROM_EMAIL, [claim.parent_email])
|
||||
message.attach_alternative(html_body, "text/html")
|
||||
|
||||
try:
|
||||
send_mail(subject, body, settings.DEFAULT_FROM_EMAIL, [claim.parent_email], fail_silently=False)
|
||||
message.send(fail_silently=False)
|
||||
except OSError:
|
||||
# Anything the mail backend raises for an unreachable server or a refused
|
||||
# connection. The link stands; the club can resend from the queue.
|
||||
|
||||
58
members/templates/members/email/claim_approved.html
Normal file
58
members/templates/members/email/claim_approved.html
Normal file
@@ -0,0 +1,58 @@
|
||||
{% extends "email/_base.html" %}
|
||||
{% load i18n club_email %}
|
||||
|
||||
{% comment %}
|
||||
HTML sibling of claim_approved.txt -- same content, same context (club,
|
||||
child, parent_first_name, set_password_url), just laid out for an inbox
|
||||
instead of a terminal. Kept in lockstep with the .txt version by hand:
|
||||
there's no single source the two are generated from, so a change to one
|
||||
reads as incomplete without the other.
|
||||
{% endcomment %}
|
||||
|
||||
{% block title %}{% blocktrans with club=club.name %}Your {{ club }} account is ready{% endblocktrans %}{% endblock title %}
|
||||
|
||||
{% block preheader %}{% blocktrans with club=club.name %}{{ club }} has confirmed you're a parent or guardian -- set your password to sign in.{% endblocktrans %}{% endblock preheader %}
|
||||
|
||||
{% block header %}
|
||||
{% absolute_media_url club.logo as logo_url %}
|
||||
<table role="presentation" cellpadding="0" cellspacing="0" border="0">
|
||||
<tr>
|
||||
<td valign="middle">
|
||||
{% if club.logo %}
|
||||
<img src="{{ logo_url }}" alt="{{ club.name }}" width="48" height="48" style="display:block; width:48px; height:48px; border-radius:24px; object-fit:contain; background-color:#f3f4f6;">
|
||||
{% else %}
|
||||
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="48" style="width:48px;">
|
||||
<tr>
|
||||
<td align="center" valign="middle" width="48" height="48" bgcolor="{{ club.secondary_color|default:"#ec4899" }}" style="width:48px; height:48px; border-radius:24px; background-color:{{ club.secondary_color|default:"#ec4899" }}; color:{{ club.secondary_content_color|default:"#ffffff" }}; font-family: Arial, Helvetica, sans-serif; font-size:16px; font-weight:bold;">
|
||||
{{ club.initials }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td style="padding-left:14px;" valign="middle">
|
||||
<span style="font-family: Arial, Helvetica, sans-serif; font-size:18px; font-weight:bold; color:#111827;">{{ club.name }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
{% endblock header %}
|
||||
|
||||
{% block content %}
|
||||
<p style="margin:0 0 16px 0;">{% blocktrans with name=parent_first_name %}Hello {{ name }},{% endblocktrans %}</p>
|
||||
|
||||
<p style="margin:0 0 20px 0;">{% blocktrans with club=club.name child=child %}{{ club }} has confirmed that you're {{ child }}'s parent or guardian, and your account is ready.{% endblocktrans %}</p>
|
||||
|
||||
{% trans "Set your password" as set_password_label %}
|
||||
{% include "email/_button.html" with href=set_password_url label=set_password_label bg=club.primary_color|default:"#4f46e5" fg=club.primary_content_color|default:"#ffffff" %}
|
||||
|
||||
<p style="margin:0 0 16px 0; font-size:13px; color:#6b7280;">{% trans "That link is for you alone — please don't forward it." %}</p>
|
||||
|
||||
<p style="margin:0;">{% trans "Once you're signed in you'll see the children linked to you." %}</p>
|
||||
{% endblock content %}
|
||||
|
||||
{% block footer %}
|
||||
{% if club.contact_email %}
|
||||
<p style="margin:0 0 8px 0;">{% blocktrans with email=club.contact_email %}Something not right? Reply to this note or write to {{ email }}.{% endblocktrans %}</p>
|
||||
{% endif %}
|
||||
<p style="margin:0;">{% blocktrans with club=club.name %}— {{ club }}{% endblocktrans %}</p>
|
||||
{% endblock footer %}
|
||||
Reference in New Issue
Block a user