From 607536461d00d3ebc8cc8a2878e974940d604d22 Mon Sep 17 00:00:00 2001 From: gajjug004 Date: Tue, 6 Oct 2026 17:12:46 +0530 Subject: [PATCH 1/4] feat: branded TriviaTap emails with a support address Auth mails use a TriviaTap wrapper instead of frappe's generic one, show developers@bwh.tech for help and set it as Reply-To. --- progress.md | 13 ++++ trivia_tap/email_code.py | 4 +- .../templates/emails/trivia_tap_wrapper.html | 63 +++++++++++++++++++ trivia_tap/tests/test_auth.py | 19 +++++- 4 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 trivia_tap/templates/emails/trivia_tap_wrapper.html diff --git a/progress.md b/progress.md index f380fef..2d61601 100644 --- a/progress.md +++ b/progress.md @@ -1,5 +1,18 @@ # Progress +## Branded emails (2026-10-06) + +### Done + +- `templates/emails/trivia_tap_wrapper.html`: TriviaTap wrapper for every auth mail. Dark masthead with logo, mint stripe, white card, brand green button, code in a dashed box, and a "Need help?" footer pointing to developers@bwh.tech. +- `send_mail` sets Reply-To to developers@bwh.tech, so a reply reaches support instead of noreply. +- Test: the queued mail carries the logo, the support link and the Reply-To header. + +### Notes + +- Styles live in the wrapper's ` + + + + + + + + + + + diff --git a/trivia_tap/tests/test_auth.py b/trivia_tap/tests/test_auth.py index f8b80e9..29a4efb 100644 --- a/trivia_tap/tests/test_auth.py +++ b/trivia_tap/tests/test_auth.py @@ -1,3 +1,4 @@ +from email import message_from_string from unittest.mock import patch from urllib.parse import parse_qs, urlsplit @@ -16,7 +17,7 @@ send_reset_link, sign_up, ) -from trivia_tap.email_code import MAX_TRIES +from trivia_tap.email_code import MAX_TRIES, send_mail from trivia_tap.patches import brand_site EMAIL = "new.host@example.com" @@ -303,3 +304,19 @@ def test_google_sign_up_lands_as_a_quiz_host(self): self.assertIn("Quiz Host", frappe.get_roles(EMAIL)) self.assertEqual(user.user_type, "System User") self.assertEqual(user.get_social_login_userid("google"), "google-123") + + +class TestMail(IntegrationTestCase): + def test_mail_carries_the_brand_and_support_address(self): + send_mail(EMAIL, "Your TriviaTap log in code", "trivia_tap_code", {"code": "042917", "minutes": 10}) + + mime = message_from_string(frappe.get_last_doc("Email Queue").message) + self.assertEqual(mime["Reply-To"], "developers@bwh.tech") + message = ( + next(part for part in mime.walk() if part.get_content_type() == "text/html") + .get_payload(decode=True) + .decode() + ) + self.assertIn("042917", message) + self.assertIn("trivia-tap-logo.png", message) + self.assertIn("mailto:developers@bwh.tech", message) From 008453f2889014b703e974437d66ed792eafce75 Mon Sep 17 00:00:00 2001 From: gajjug004 Date: Tue, 6 Oct 2026 17:16:21 +0530 Subject: [PATCH 2/4] feat: center the email code in a full width box --- trivia_tap/templates/emails/trivia_tap_wrapper.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trivia_tap/templates/emails/trivia_tap_wrapper.html b/trivia_tap/templates/emails/trivia_tap_wrapper.html index 05f5c20..18f153f 100644 --- a/trivia_tap/templates/emails/trivia_tap_wrapper.html +++ b/trivia_tap/templates/emails/trivia_tap_wrapper.html @@ -19,7 +19,7 @@ .tt-page .tt-content { padding: 32px; } .tt-page .email-title { margin: 0 0 16px; font-family: "Bricolage Grotesque", "Instrument Sans", Helvetica, Arial, sans-serif; font-size: 24px; font-weight: 800; line-height: 1.25; letter-spacing: -0.01em; color: #0a100e; } .tt-page .email-body p { margin: 0 0 20px !important; font-size: 15px; line-height: 1.6; color: #3d4a44; } - .tt-page .email-body .email-code { display: inline-block; margin: 0 0 24px; padding: 14px 22px; font-family: "Martian Mono", "SF Mono", Menlo, Consolas, monospace; font-size: 30px; font-weight: 700; letter-spacing: 0.2em; color: #0a100e; background-color: #eef8f3; border: 1px dashed #11ddb9; border-radius: 12px; } + .tt-page .email-body .email-code { display: block; margin: 0 0 24px; padding: 18px 0; text-align: center; text-indent: 0.2em; font-family: "Martian Mono", "SF Mono", Menlo, Consolas, monospace; font-size: 30px; font-weight: 700; letter-spacing: 0.2em; color: #0a100e; background-color: #eef8f3; border: 1px dashed #11ddb9; border-radius: 12px; } .tt-page .email-body .email-action { margin: 4px 0 24px; } .tt-page .email-body .email-btn { display: inline-block; padding: 13px 24px; font-size: 15px; font-weight: 600 !important; line-height: 1; text-decoration: none !important; color: #0a100e !important; background-color: #20eea0; border-radius: 999px; border: 0; } .tt-page .email-body .email-ignore { margin: 0 !important; font-size: 13px; color: #6b7a73; } From 3c56fe920ea69396c2e8577e61cec47d22aad258 Mon Sep 17 00:00:00 2001 From: gajjug004 Date: Tue, 6 Oct 2026 17:25:00 +0530 Subject: [PATCH 3/4] feat: dark email design to match the app --- progress.md | 3 +- .../templates/emails/trivia_tap_wrapper.html | 44 +++++++++---------- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/progress.md b/progress.md index 2d61601..87fc19c 100644 --- a/progress.md +++ b/progress.md @@ -4,13 +4,14 @@ ### Done -- `templates/emails/trivia_tap_wrapper.html`: TriviaTap wrapper for every auth mail. Dark masthead with logo, mint stripe, white card, brand green button, code in a dashed box, and a "Need help?" footer pointing to developers@bwh.tech. +- `templates/emails/trivia_tap_wrapper.html`: TriviaTap wrapper for every auth mail, dark like the app. Near-black card with logo and name, white title, code centered in a mint gradient box, mint gradient pill button, and a "Need help?" footer pointing to developers@bwh.tech. Picked over a minimal light and a playful mascot design. - `send_mail` sets Reply-To to developers@bwh.tech, so a reply reaches support instead of noreply. - Test: the queued mail carries the logo, the support link and the Reply-To header. ### Notes - Styles live in the wrapper's ` - + - From c8b00fa9772567e7bf09b4638bc39bd336bd5d4f Mon Sep 17 00:00:00 2001 From: gajjug004 Date: Tue, 6 Oct 2026 17:31:13 +0530 Subject: [PATCH 4/4] test: check the email without an outgoing email account CI sites have no Email Account, so frappe.sendmail throws there. Capture the call and render it with get_formatted_html instead. --- trivia_tap/tests/test_auth.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/trivia_tap/tests/test_auth.py b/trivia_tap/tests/test_auth.py index 29a4efb..5c84248 100644 --- a/trivia_tap/tests/test_auth.py +++ b/trivia_tap/tests/test_auth.py @@ -1,9 +1,10 @@ -from email import message_from_string from unittest.mock import patch from urllib.parse import parse_qs, urlsplit import frappe +from frappe.email.email_body import get_formatted_html from frappe.tests import IntegrationTestCase +from frappe.utils.jinja import get_email_from_template from frappe.utils.oauth import consume_oauth_state, update_oauth_user from frappe.utils.password import check_password @@ -307,16 +308,14 @@ def test_google_sign_up_lands_as_a_quiz_host(self): class TestMail(IntegrationTestCase): - def test_mail_carries_the_brand_and_support_address(self): + @patch("trivia_tap.email_code.frappe.sendmail") + def test_mail_carries_the_brand_and_support_address(self, sendmail): send_mail(EMAIL, "Your TriviaTap log in code", "trivia_tap_code", {"code": "042917", "minutes": 10}) - mime = message_from_string(frappe.get_last_doc("Email Queue").message) - self.assertEqual(mime["Reply-To"], "developers@bwh.tech") - message = ( - next(part for part in mime.walk() if part.get_content_type() == "text/html") - .get_payload(decode=True) - .decode() - ) + mail = sendmail.call_args.kwargs + self.assertEqual(mail["reply_to"], "developers@bwh.tech") + content = get_email_from_template(mail["template"], mail["args"])[0] + message = get_formatted_html(mail["subject"], content, wrapper=mail["wrapper"]) self.assertIn("042917", message) self.assertIn("trivia-tap-logo.png", message) self.assertIn("mailto:developers@bwh.tech", message)