Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Email template revamp #847

Merged
merged 5 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 52 additions & 19 deletions backend/src/appointment/controller/mailer.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,18 @@ def text(self):
return self.body_plain if self.body_plain != '' else escape(self.body_html)

def _attachments(self):
"""provide all attachments as list"""
return self.attachments
"""provide all attachments as list, add tbpro logo to every mail"""
with open('src/appointment/templates/assets/img/tbpro_logo.png', 'rb') as fh:
tbpro_logo = fh.read()

return [
Attachment(
mime=('image', 'png'),
filename='tbpro_logo.png',
data=tbpro_logo,
),
*self.attachments,
]

def build(self):
"""build email header, body and attachments"""
Expand Down Expand Up @@ -204,6 +214,7 @@ def _attachments(self):
clock_icon = fh.read()

return [
*super()._attachments(),
Attachment(
mime=('image', 'png'),
filename='calendar.png',
Expand All @@ -214,7 +225,6 @@ def _attachments(self):
filename='clock.png',
data=clock_icon,
),
*self.attachments,
]


Expand All @@ -239,9 +249,10 @@ def html(self):
timezone=self.timezone,
day=self.day,
duration=self.duration,
# Icon cids
calendar_icon_cid=self._attachments()[0].filename,
clock_icon_cid=self._attachments()[1].filename,
# Image cids
tbpro_logo_cid=self._attachments()[0].filename,
calendar_icon_cid=self._attachments()[1].filename,
clock_icon_cid=self._attachments()[2].filename,
)


Expand All @@ -256,7 +267,10 @@ def __init__(self, appointment_title, *args, **kwargs):
self.appointment_title = appointment_title

def html(self):
return get_template('errors/zoom_invite_failed.jinja2').render(title=self.appointment_title)
return get_template('errors/zoom_invite_failed.jinja2').render(
title=self.appointment_title,
tbpro_logo_cid=self._attachments()[0].filename,
)

def text(self):
return l10n('zoom-invite-failed-plain', {'title': self.appointment_title})
Expand Down Expand Up @@ -301,9 +315,10 @@ def html(self):
deny=self.denyUrl,
schedule_name=self.schedule_name,
lang=self.lang,
# Icon cids
calendar_icon_cid=self._attachments()[0].filename,
clock_icon_cid=self._attachments()[1].filename,
# Image cids
tbpro_logo_cid=self._attachments()[0].filename,
calendar_icon_cid=self._attachments()[1].filename,
clock_icon_cid=self._attachments()[2].filename,
)


Expand All @@ -323,7 +338,11 @@ def text(self):
return l10n('reject-mail-plain', {'owner_name': self.owner_name, 'date': self.date})

def html(self):
return get_template('rejected.jinja2').render(owner_name=self.owner_name, date=self.date)
return get_template('rejected.jinja2').render(
owner_name=self.owner_name,
date=self.date,
tbpro_logo_cid=self._attachments()[0].filename,
)


class PendingRequestMail(Mailer):
Expand All @@ -340,7 +359,11 @@ def text(self):
return l10n('pending-mail-plain', {'owner_name': self.owner_name, 'date': self.date})

def html(self):
return get_template('pending.jinja2').render(owner_name=self.owner_name, date=self.date)
return get_template('pending.jinja2').render(
owner_name=self.owner_name,
date=self.date,
tbpro_logo_cid=self._attachments()[0].filename,
)


class NewBookingMail(BaseBookingMail):
Expand Down Expand Up @@ -374,9 +397,10 @@ def html(self):
day=self.day,
duration=self.duration,
schedule_name=self.schedule_name,
# Icon cids
calendar_icon_cid=self._attachments()[0].filename,
clock_icon_cid=self._attachments()[1].filename,
# Image cids
tbpro_logo_cid=self._attachments()[0].filename,
calendar_icon_cid=self._attachments()[1].filename,
clock_icon_cid=self._attachments()[2].filename,
)


Expand Down Expand Up @@ -411,12 +435,15 @@ def html(self):
requestee_email=self.requestee_email,
topic=self.topic,
details=self.details,
tbpro_logo_cid=self._attachments()[0].filename,
)


class InviteAccountMail(Mailer):
def __init__(self, *args, **kwargs):
default_kwargs = {'subject': l10n('new-account-mail-subject')}
def __init__(self, date, *args, **kwargs):
self.date = date
lang = kwargs['lang'] if 'lang' in kwargs else None
default_kwargs = {'subject': l10n('new-account-mail-subject', lang=lang)}
super(InviteAccountMail, self).__init__(*args, **default_kwargs, **kwargs)

def text(self):
Expand All @@ -428,7 +455,12 @@ def text(self):
)

def html(self):
return get_template('new_account.jinja2').render(homepage_url=os.getenv('FRONTEND_URL'))
return get_template('new_account.jinja2').render(
date=self.date,
lang=self.lang,
homepage_url=os.getenv('FRONTEND_URL'),
tbpro_logo_cid=self._attachments()[0].filename,
)


class ConfirmYourEmailMail(Mailer):
Expand All @@ -450,5 +482,6 @@ def text(self):
def html(self):
return get_template('confirm_email.jinja2').render(
confirm_email_url=self.confirm_url,
decline_email_url=self.decline_url
decline_email_url=self.decline_url,
tbpro_logo_cid=self._attachments()[0].filename,
)
35 changes: 21 additions & 14 deletions backend/src/appointment/l10n/de/email.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,20 @@
-brand-slogan = Weniger planen, mehr schaffen.
-brand-sign-up-with-url = Registrieren auf appointment.day
-brand-sign-up-with-no-url = Registrieren auf
-brand-footer = Diese Nachricht wurde gesendet von:
{-brand-name}
{-brand-slogan} {-brand-sign-up-with-url}
-brand-footer = Du erhälst diese E-Mail, weil Du dich auf unserer Website für Thunderbird Appointment Beta angemeldet hast.

Copyright © 2025 MZLA Technologies. All rights reserved.
MZLA Technologies 149 New Montgomery St., 4th Floor San Francisco, CA 94501 USA

mail-brand-contact-form = Kontaktformular
mail-brand-support-hint = Du hast Fragen? Wir helfen gern. Nutze unser { $contact_form_link }, oder antworte einfach auf diese E-Mail für Support.
mail-brand-support-hint = Du hast Fragen? Wir helfen gern. Antworte einfach auf diese E-Mail für Support.
mail-brand-reply-hint = Du hast Fragen? Wir helfen gern, Du erreichst uns über unser { $contact_form_link }.
mail-brand-reply-hint-attendee-info = Du möchtest { $name } kontaktieren? Antworte einfach auf diese E-Mail.

mail-brand-footer = Diese Nachricht wurde gesendet von:
{-brand-name}
{-brand-slogan} {-brand-sign-up-with-no-url}
mail-brand-footer = Du erhälst diese E-Mail, weil Du dich auf unserer Website für Thunderbird Appointment Beta angemeldet hast.

Copyright © 2025 MZLA Technologies. All rights reserved.
MZLA Technologies 149 New Montgomery St., 4th Floor San Francisco, CA 94501 USA

## Invitation

Expand Down Expand Up @@ -164,15 +166,20 @@ support-mail-plain = { $requestee_name } ({ $requestee_email }) hat folgende Sup

## New/Invited Account Email
new-account-mail-subject = Du wurdest zu Thunderbird Appointment eingeladen
new-account-mail-action = Weiter zu Thunderbird Appointment
new-account-mail-html-heading = Du wurdest zu Thunderbird Appointment eingeladen.
new-account-mail-html-body = Logge dich mit dieser E-Mail-Adresse ein um fortzufahren.
new-account-mail-action = Registrieren
new-account-mail-html-heading = Vielen Dank, dass Du dich als einer der ersten Tester von Thunderbird Appointment Beta registrierst.
Wir freuen uns, dass Du dabei bist!
new-account-mail-html-body = Deine E-Mail-Adresse wurde am { $date } auf unsere Beta-Warteliste gesetzt.
new-account-mail-html-body-2 = Melde Dich an und beginne mit der Nutzung von Appointment, indem Du auf die Schaltfläche unten klickst oder diesen Link in Deinen Browser einfügst:

# Variables:
# $homepage_url (String) - URL to Thunderbird Appointment
new-account-mail-plain = Du wurdest zu Thunderbird Appointment eingeladen.
Logge dich mit dieser E-Mail-Adresse ein um fortzufahren.
{ $homepage_url }
{-brand-footer}
new-account-mail-plain = Vielen Dank, dass Du dich als einer der ersten Tester von Thunderbird Appointment Beta registrierst.
Wir freuen uns, dass Du dabei bist!
Deine E-Mail-Adresse wurde am { $date } auf unsere Beta-Warteliste gesetzt.
Melde Dich an und beginne mit der Nutzung von Appointment, indem Du auf die Schaltfläche unten klickst oder diesen Link in Deinen Browser einfügst:
{ $homepage_url }
{-brand-footer}

## Confirm Email for waiting list
confirm-email-mail-subject = Bestätige deine E-Mail-Adresse um der Warteliste beizutreten!
Expand Down
37 changes: 23 additions & 14 deletions backend/src/appointment/l10n/en/email.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,22 @@
-brand-slogan = Plan less, do more.
-brand-sign-up-with-url = Sign up on appointment.day
-brand-sign-up-with-no-url = Sign up on
-brand-footer = This message was sent from:
{-brand-name}
{-brand-slogan} {-brand-sign-up-with-url}
-brand-footer = You are receiving this email because you signed up on our website for the Thunderbird Appointment Beta.

Copyright © 2025 MZLA Technologies. All rights reserved.
MZLA Technologies 149 New Montgomery St., 4th Floor San Francisco, CA 94501 USA

mail-brand-contact-form = contact form
mail-brand-support-hint = Got questions? We're here to help. Fill out our { $contact_form_link }, or simply reply to this email for support.
mail-brand-support-hint = Got questions? We're here to help. Simply reply to this email for support.
mail-brand-reply-hint = Got questions? We're here to help, you can reach us via our { $contact_form_link }.
mail-brand-reply-hint-attendee-info = Need to get in touch with { $name }? Simply reply to this email.

mail-brand-footer = This message was sent from:
{-brand-name}
{-brand-slogan} {-brand-sign-up-with-no-url}
mail-brand-footer = You are receiving this email because you signed up on our website for the Thunderbird Appointment Beta.

Copyright © 2025 MZLA Technologies. All rights reserved.
MZLA Technologies 149 New Montgomery St., 4th Floor San Francisco, CA 94501 USA
mail-brand-footer-privacy = Privacy
mail-brand-footer-legal = Legal

## Invitation

Expand Down Expand Up @@ -164,15 +168,20 @@ support-mail-plain = { $requestee_name } ({ $requestee_email }) sent the followi

## New/Invited Account Email
new-account-mail-subject = You've been invited to Thunderbird Appointment
new-account-mail-action = Log In
new-account-mail-html-heading = You've been invited to Thunderbird Appointment.
new-account-mail-html-body = Login with this email address to continue.
new-account-mail-action = Sign Up
new-account-mail-html-heading = Thank you for signing up to be one of the earliest testers of Thunderbird Appointment Beta.
We’re excited to have you on board!
new-account-mail-html-body = You added your email to our beta wait-list on { $date }.
new-account-mail-html-body-2 = Sign in and start using Appointment by clicking the button below or pasting this link into your browser:

# Variables:
# $homepage_url (String) - URL to Thunderbird Appointment
new-account-mail-plain = You've been invited to Thunderbird Appointment.
Login with this email address to continue.
{ $homepage_url }
{-brand-footer}
new-account-mail-plain = Thank you for signing up to be one of the earliest testers of Thunderbird Appointment Beta.
We’re excited to have you on board!
You added your email to our beta wait-list on { $date }.
Sign in and start using Appointment by clicking the button below or pasting this link into your browser:
{ $homepage_url }
{-brand-footer}

## Confirm Email for waiting list
confirm-email-mail-subject = Confirm your email to join the waiting list!
Expand Down
2 changes: 1 addition & 1 deletion backend/src/appointment/routes/invite.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,6 @@ def send_invite_email(
db.add(invite_code)
db.commit()

background_tasks.add_task(send_invite_account_email, to=email)
background_tasks.add_task(send_invite_account_email, to=email, lang=subscriber.language)

return invite_code
9 changes: 7 additions & 2 deletions backend/src/appointment/routes/waiting_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def act_on_waiting_list(data: schemas.TokenForWaitingList, db: Session = Depends
}


""" ADMIN ROUTES
""" ADMIN ROUTES
These require get_admin_subscriber!
"""

Expand Down Expand Up @@ -170,7 +170,12 @@ def invite_waiting_list_users(
db.add(invite_code)
db.commit()

background_tasks.add_task(send_invite_account_email, to=subscriber.email)
background_tasks.add_task(
send_invite_account_email,
date=waiting_list_user.time_created,
to=subscriber.email,
lang=subscriber.language
)
accepted.append(waiting_list_user.id)

if posthog:
Expand Down
4 changes: 2 additions & 2 deletions backend/src/appointment/tasks/emails.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,9 @@ def send_support_email(requestee_name, requestee_email, topic, details):
sentry_sdk.capture_exception(e)


def send_invite_account_email(to):
def send_invite_account_email(date, to, lang):
try:
mail = InviteAccountMail(to=to)
mail = InviteAccountMail(date=date, to=to, lang=lang)
mail.send()
except Exception as e:
if os.getenv('APP_ENV') == APP_ENV_DEV:
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 12 additions & 17 deletions backend/src/appointment/templates/email/includes/base.jinja2
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
{# Helper vars! These are accessible from any template that extends base #}
{% set colour_surface_base = '#FEFFFF' %}
{% set colour_surface_raised = '#FEFFFF' %}
{% set colour_text_base = '#18181B' %}
{% set colour_text_base = '#1A202C' %}
{% set colour_text_muted = '#737584' %}
{% set colour_icon_secondary = '#4C4D58' %}
{% set colour_neutral = '#FEFFFF' %}
{% set colour_tbpro_apmt_primary = '#008080' %}
{% set colour_tbpro_apmt_primary_hover = '#066769' %}
{% set colour_tbpro_apmt_secondary = '#81D4B5' %}
{% set colour_tbpro_apmt_soft = '#F3F9FC' %}
{% set logo_image = '<img style="width: 256px;" alt="" src="cid:%(cid)s" />'|format(cid=tbpro_logo_cid) %}

<html lang="{{ l10n('locale', lang=lang if lang else None) }}" style="
font-size: 13px;
color: {{ colour_text_base }};
Expand All @@ -16,6 +19,7 @@
margin: 24px 0;
">
<body>
<div style="text-align: center; margin-bottom: 16px;">{{ logo_image|safe }}</div>
{% if self.introduction()|trim %}
<div style="
margin-left: auto;
Expand All @@ -27,14 +31,15 @@
{% endif %}
{% if self.information()|trim %}
<div style="
box-sizing: border-box;
margin-left: auto;
margin-right: auto;
margin-bottom: 24px;
max-width: 310px;
margin-bottom: 16px;
max-width: 576px;
border: 1px solid {{ colour_tbpro_apmt_primary }};
border-radius: 6px;
padding: 12px;
background-color: {{ colour_surface_raised }}
border-radius: 12px;
padding: 16px 46px;
background-color: {{ colour_tbpro_apmt_soft }}
">
{% block information %}{% endblock %}
</div>
Expand All @@ -45,9 +50,8 @@
</div>
{% endif %}
{% if show_contact_form_support_hint %}
{% set link = '<a href="%(url)s">%(label)s</a>'|format(url=homepage_url + '/contact', label=l10n('mail-brand-contact-form', lang=lang if lang else None)) %}
<div style="text-align: center; margin-left: auto; margin-right: auto; margin-bottom: 24px; padding: 12px; max-width: 310px;">
{{ l10n('mail-brand-support-hint', {'contact_form_link': link}, lang if lang else None)|safe }}
{{ l10n('mail-brand-support-hint', lang=lang if lang else None)|safe }}
</div>
{% endif %}
{% if show_contact_form_reply_hint %}
Expand All @@ -58,15 +62,6 @@
{{ l10n('mail-brand-reply-hint', {'contact_form_link': link}, lang if lang else None)|safe }}
</div>
{% endif %}
<div style="
display: block;
width: 100%;
padding-bottom: 1px;
border-radius: unset;
margin-top: 12px;
margin-bottom: 12px;
background: linear-gradient(90deg, rgba(21, 66, 124, 0) 20.5%, rgba(21, 66, 124, 0.2) 50%, rgba(21, 66, 124, 0) 79.5%);
"></div>
{% include './includes/footer.jinja2' %}
</body>
</html>
Loading