Customize email templates for Magic Link, verification, password reset, and 2FA.
BetterAuth includes 4 default email templates:
Create your custom templates in your Symfony project:
templates/
└── emails/
└── betterauth/
├── magic_link.html.twig
├── email_verification.html.twig
├── password_reset.html.twig
└── two_factor_code.html.twig
Start by copying the default template:
cp vendor/betterauth/symfony-bundle/src/Resources/views/emails/magic_link.html.twig \
templates/emails/betterauth/magic_link.html.twig
{# templates/emails/betterauth/magic_link.html.twig #}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Sign In to {{ app_name }}</title>
</head>
<body style="font-family: Arial, sans-serif; background-color: #f4f4f4;">
<div style="max-width: 600px; margin: 0 auto; padding: 20px;">
<img src="{{ asset('images/logo.png') }}" alt="Logo" style="max-width: 200px;">
<h1>Your Magic Link</h1>
<p>Click the button below to sign in:</p>
<a href="{{ magicLink }}" style="display: inline-block; padding: 12px 24px; background-color: #007bff; color: white; text-decoration: none; border-radius: 4px;">
Sign In
</a>
<p style="color: #999; font-size: 12px;">
This link expires in 10 minutes.
</p>
</div>
</body>
</html>
magicLink - The full URL for passwordless loginverificationLink - The full URL to verify the email addressresetLink - The full URL to reset the passwordcode - The 6-digit 2FA codeBetterAuth looks for templates in this order:
templates/emails/betterauth/{template} (highest priority)[@BetterAuth](https://github.com/BetterAuth)/emails/{template} (fallback)Use inline CSS and table-based layouts for maximum email client compatibility:
<table role="presentation" style="width: 100%; border-collapse: collapse;">
<tr>
<td style="padding: 20px;">
{# Your content #}
</td>
</tr>
</table>
Test your templates in:
Use MailHog or MailCatcher:
MAILER_DSN=smtp://localhost:1025
Then view emails at http://localhost:8025
// src/Controller/DevController.php
#[Route('/dev/email-preview/{template}')]
public function previewEmail(string $template, Environment $twig): Response
{
$html = $twig->render("emails/betterauth/{$template}.html.twig", [
'magicLink' => 'https://example.com/auth/magic-link?token=xxx',
'verificationLink' => 'https://example.com/verify?token=xxx',
'resetLink' => 'https://example.com/reset?token=xxx',
'code' => '123456',
]);
return new Response($html);
}
<img src="{{ absolute_url(asset('images/logo.png')) }}"
alt="Company Logo"
style="max-width: 200px; margin-bottom: 20px;">
<a href="{{ magicLink }}"
style="display: inline-block;
padding: 15px 30px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #ffffff;
text-decoration: none;
border-radius: 8px;
font-weight: bold;">
Sign In to Your Account
</a>
<div style="margin-top: 40px; padding-top: 20px; border-top: 1px solid #eee; color: #999; font-size: 12px;">
<p>© 2025 Your Company. All rights reserved.</p>
<p>
<a href="https://yourcompany.com" style="color: #999;">Website</a> |
<a href="https://yourcompany.com/privacy" style="color: #999;">Privacy</a>
</p>
</div>
php bin/console cache:cleartemplates/emails/betterauth/Use correct variable names (case-sensitive):
{{ magicLink }}{{ verificationLink }}{{ resetLink }}{{ code }}How can I help you explore Laravel packages today?