Yes, you can use FreeMarker logic in FusionAuth email templates to dynamically customize content per tenant without duplicating templates.
SolutionStore tenant-specific branding data in the tenant.data field (custom JSON). For example:
{ "branding": { "logoUrl": "https://cdn.example.com/acme/logo.png", "primaryColor": "#0057b8", "buttonTextColor": "#ffffff", "subjectPrefix": "[Acme]", "supportEmail": "help@acme.com", "companyName": "Acme" } }Then reference this data in your email templates using FreeMarker syntax. Here's an example for email verification:
[#assign b = (tenant.data.branding)!{}] [#assign color = b.primaryColor!"#333333"] <div style="font-family: Arial, sans-serif;"> <img src="${b.logoUrl!'https://cdn.example.com/default-logo.png'}" alt="${b.companyName!tenant.name}" height="40"> <p>Hi ${user.firstName!'there'},</p> [#if verificationOneTimeCode??] <p>Your verification code:</p> <p><strong>${verificationOneTimeCode}</strong></p> [#else] [#assign url = "${baseUrl}/email/verify/${verificationId}?client_id=${(application.oauthConfiguration.clientId)!''}&tenantId=${tenant.id}"] <a href="${url?html}" style="background:${color}; color:${b.buttonTextColor!'#ffffff'}; padding:12px 24px; text-decoration:none; border-radius:4px;"> Verify email </a> [/#if] </div> How it works [#assign b = (tenant.data.branding)!{}] safely extracts the branding object or defaults to an empty object ${b.logoUrl!'default-value'} provides fallback values if a property is missing The same template works across all tenants, pulling each tenant's specific branding from tenant.dataThis approach works for all FusionAuth email templates (email verification, forgot password, email MFA). The complexity and depth of customization you can achieve depends on your specific needs, but this pattern handles most common branding requirements.
There's no form for editing tenant data, but you can do so using one of the client libraries and your own custom form.