4 Commits
Author SHA1 Message Date
FrankandClaude Sonnet 5 c4e5139ec4 Increase email header logo size from 40px to 140px
40px made the logo too small in the header banner.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-04 14:55:15 +02:00
FrankandClaude Sonnet 5 238705495e 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>
2026-07-04 14:51:34 +02:00
FrankandClaude Sonnet 5 4a5d83ef53 Fix duplicate EmailLog rows for a single sent email
Mailer dispatches MessageEvent twice when routed through Messenger:
once when queuing (queued=true) and once on the actual send from the
worker (queued=false). EmailLoggerListener logged on both, creating
two rows per email actually sent. Skip the queued dispatch.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-04 14:44:03 +02:00
FrankandClaude Sonnet 5 0e12e7fa8f Switch docker/.env.dist mailer template from SendGrid to Mailgun
The project now sends mail via Mailgun (symfony/mailgun-mailer), not
SendGrid, so the tracked template should reflect the real transport
in use.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-04 14:23:21 +02:00
5 changed files with 99 additions and 16 deletions
+3 -1
View File
@@ -7,7 +7,9 @@ APP_ENV=prod
SITE_BASE_URL=https://escapepage.com
# Mailer
MAILER_DSN=sendgrid://CHANGEME_SENDGRID_API_KEY@default
MAILGUN_API_KEY=CHANGEME_MAILGUN_API_KEY
MAILGUN_DOMAIN=CHANGEME_MAILGUN_DOMAIN
MAILER_DSN=mailgun+api://CHANGEME_MAILGUN_API_KEY:CHANGEME_MAILGUN_DOMAIN@default?region=eu
MAILER_FROM=mailer@escapepage.nl
# Database
@@ -22,6 +22,10 @@ class EmailLoggerListener
public function onMessage(MessageEvent $event): void
{
if ($event->isQueued()) {
return;
}
$message = $event->getMessage();
if (!$message instanceof TemplatedEmail) {
return;
+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="140" 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 %}