Add shared HTML layout for transactional emails

confirmation_email.html.twig and reset_password/email.html.twig were
plain unstyled HTML with no shared structure. Extract a table-based
layout (templates/emails/layout.html.twig) with header/logo, content
block, and footer, so future transactional emails can extend it
instead of starting from scratch.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Frank
2026-07-04 14:51:34 +02:00
co-authored by Claude Sonnet 5
parent 4a5d83ef53
commit 238705495e
3 changed files with 92 additions and 15 deletions
+33
View File
@@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="{{ app.request ? app.request.locale : 'en' }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}{{ 'site.name'|trans }}{% endblock %}</title>
</head>
<body style="margin:0; padding:0; background-color:#f2f4f6; font-family:Arial, Helvetica, sans-serif;">
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background-color:#f2f4f6; padding:24px 0;">
<tr>
<td align="center">
<table role="presentation" width="600" cellpadding="0" cellspacing="0" style="max-width:600px; width:100%; background-color:#ffffff; border-radius:8px; overflow:hidden;">
<tr>
<td align="center" style="background-color:#3a7ca5; padding:24px;">
<img src="{{ absolute_url(asset('images/logo.png')) }}" alt="{{ 'site.name'|trans }}" height="40" style="display:block; border:0;">
</td>
</tr>
<tr>
<td style="padding:32px; color:#333333; font-size:15px; line-height:1.6;">
{% block content %}{% endblock %}
</td>
</tr>
<tr>
<td style="padding:16px 32px; background-color:#f2f4f6; color:#8a8f98; font-size:12px; text-align:center;">
&copy; {{ "now"|date("Y") }} {{ 'site.name'|trans }}
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
@@ -1,12 +1,34 @@
<h1>Hi! Please confirm your email!</h1>
{% extends 'emails/layout.html.twig' %}
<p>
Please confirm your email address by clicking the following link: <br><br>
<a href="{{ signedUrl }}">Confirm my Email</a>.
This link will expire in {{ expiresAtMessageKey|trans(expiresAtMessageData, 'VerifyEmailBundle') }}.
If the link has expired or doesn't work, you can <a href="{{ url('app_verify_resend_email') }}">request a new one</a>.
</p>
{% block title %}Confirm your email{% endblock %}
<p>
Cheers!
</p>
{% block content %}
<h1 style="margin:0 0 16px; font-size:20px; color:#222222;">Hi! Please confirm your email</h1>
<p style="margin:0 0 24px;">
Thanks for signing up. Please confirm your email address by clicking the button below.
This link will expire in {{ expiresAtMessageKey|trans(expiresAtMessageData, 'VerifyEmailBundle') }}.
</p>
<table role="presentation" cellpadding="0" cellspacing="0" style="margin:0 0 24px;">
<tr>
<td style="border-radius:4px; background-color:#3a7ca5;">
<a href="{{ signedUrl }}" style="display:inline-block; padding:12px 24px; color:#ffffff; text-decoration:none; font-weight:bold;">
Confirm my email
</a>
</td>
</tr>
</table>
<p style="margin:0 0 24px;">
If the button doesn't work, copy and paste this link into your browser:<br>
<a href="{{ signedUrl }}" style="color:#3a7ca5; word-break:break-all;">{{ signedUrl }}</a>
</p>
<p style="margin:0 0 8px;">
If the link has expired or doesn't work, you can
<a href="{{ url('app_verify_resend_email') }}" style="color:#3a7ca5;">request a new one</a>.
</p>
<p style="margin:24px 0 0;">Cheers!</p>
{% endblock %}
+27 -5
View File
@@ -1,9 +1,31 @@
<h1>Hi!</h1>
{% extends 'emails/layout.html.twig' %}
<p>To reset your password, please visit the following link</p>
{% block title %}Reset your password{% endblock %}
<a href="{{ url('app_reset_password', {token: resetToken.token}) }}">{{ url('app_reset_password', {token: resetToken.token}) }}</a>
{% block content %}
<h1 style="margin:0 0 16px; font-size:20px; color:#222222;">Hi!</h1>
<p>This link will expire in {{ resetToken.expirationMessageKey|trans(resetToken.expirationMessageData, 'ResetPasswordBundle') }}.</p>
<p style="margin:0 0 24px;">
We received a request to reset your password. Click the button below to choose a new one.
This link will expire in {{ resetToken.expirationMessageKey|trans(resetToken.expirationMessageData, 'ResetPasswordBundle') }}.
</p>
<p>Cheers!</p>
<table role="presentation" cellpadding="0" cellspacing="0" style="margin:0 0 24px;">
<tr>
<td style="border-radius:4px; background-color:#3a7ca5;">
<a href="{{ url('app_reset_password', {token: resetToken.token}) }}" style="display:inline-block; padding:12px 24px; color:#ffffff; text-decoration:none; font-weight:bold;">
Reset my password
</a>
</td>
</tr>
</table>
<p style="margin:0 0 24px;">
If the button doesn't work, copy and paste this link into your browser:<br>
<a href="{{ url('app_reset_password', {token: resetToken.token}) }}" style="color:#3a7ca5; word-break:break-all;">{{ url('app_reset_password', {token: resetToken.token}) }}</a>
</p>
<p style="margin:0 0 8px;">If you didn't request a password reset, you can safely ignore this email.</p>
<p style="margin:24px 0 0;">Cheers!</p>
{% endblock %}