Skip to content
Menu
DevSecOps Now!!!
  • About
  • Certifications
  • Contact
  • Courses
  • DevSecOps Consulting
  • DevSecOps Tools
  • Training
  • Tutorials
DevSecOps Now!!!

Complete Guide: How to Customize and Brand Keycloak Email Templates

Posted on October 23, 2025

Limited Time Offer!

For Less Than the Cost of a Starbucks Coffee, Access All DevOpsSchool Videos on YouTube Unlimitedly.
Master DevOps, SRE, DevSecOps Skills!

Enroll Now

Introduction

Keycloak is an open-source Identity and Access Management solution that includes built-in email functionality for sending messages like password resets, email verification, and account actions.

However, the default emails are plain and generic.
To create a branded and professional experience (like Wizbrand), you can fully customize Keycloakโ€™s email templates, themes, and SMTP settings.

This tutorial walks you through:

  • Creating a custom Keycloak email theme
  • Branding Wizbrand emails with logos and colors
  • Fixing missing template errors (TemplateNotFoundException)
  • Solving SMTP configuration errors
  • Implementing safe variable usage (linkExpiration)
  • Testing and verifying with real emails

Directory Overview

Assuming a Keycloak (Quarkus-based) installation, your structure should look like this:

KEYCLOAK/
โ”œโ”€โ”€ bin/
โ”‚   โ”œโ”€โ”€ kc.sh
โ”‚   โ”œโ”€โ”€ kc.bat
โ”‚   โ”œโ”€โ”€ kcadm.sh
โ”‚   โ””โ”€โ”€ kcadm.bat
โ”œโ”€โ”€ conf/
โ”‚   โ”œโ”€โ”€ keycloak.conf
โ”‚   โ”œโ”€โ”€ truststores/
โ”‚   โ””โ”€โ”€ README.md
โ”œโ”€โ”€ data/
โ”œโ”€โ”€ lib/
โ”œโ”€โ”€ providers/
โ””โ”€โ”€ themes/
    โ”œโ”€โ”€ base/
    โ””โ”€โ”€ wizbrand-email/

The themes/ folder is where youโ€™ll add your custom Wizbrand email theme.


Step 1: Create Your Custom Theme

Create directories

Inside themes/, create a new folder named wizbrand-email:

mkdir -p themes/wizbrand-email/email/html
mkdir -p themes/wizbrand-email/email/text
mkdir -p themes/wizbrand-email/email/messages

Step 2: Configure theme.properties

File:
themes/wizbrand-email/theme.properties

# Inherit everything from the base theme
parent=base

# Import assets from the common Keycloak theme
import=common/keycloak

# Enable translations
internationalizationEnabled=true

This ensures Keycloak uses your theme but still has access to all default assets.


Step 3: Add Required Template Files

Each email type requires both an HTML and a text version.

Common template names:

email-test.ftl              (SMTP test)
password-reset.ftl          (Reset password)
email-verification.ftl      (Verify email)
execute-actions.ftl         (Admin action emails)

They must exist under:

themes/wizbrand-email/email/html/
themes/wizbrand-email/email/text/

Step 4: Fix Missing Template Errors

You may encounter:

Template not found for name "html/password-reset.ftl"

Fix: Ensure correct folder structure and move templates accordingly:

themes/wizbrand-email/email/html/password-reset.ftl
themes/wizbrand-email/email/text/password-reset.ftl

Step 5: Fix โ€œInvalidReferenceException: expiration missingโ€

Default Keycloak templates use linkExpiration, not expiration.
If you use the wrong variable, emails fail to render.

Fix the variable in both templates:

<strong>${(linkExpiration)!"a short time"}</strong>

8. Step 6: Create Your Branded HTML Templates

A. Email Verification Template (HTML)

File: themes/wizbrand-email/email/html/email-verification.ftl

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>${msg("emailVerificationSubject")!"Verify your Wizbrand email"}</title>
  </head>
  <body style="margin:0; padding:0; background-color:#f6f9fc; font-family:Arial,Helvetica,sans-serif; color:#333;">

    <table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0" style="background-color:#f6f9fc; padding:30px 0;">
      <tr>
        <td align="center">
          <table role="presentation" width="640" cellspacing="0" cellpadding="0" border="0" style="background-color:#ffffff; border-radius:12px; overflow:hidden; box-shadow:0 2px 6px rgba(0,0,0,0.05);">

            <tr>
              <td align="center" style="padding:30px 0 10px 0;">
                <img src="https://www.wizbrand.com/images/logo.png" alt="Wizbrand" width="160">
              </td>
            </tr>

            <tr>
              <td align="center" style="padding:10px 40px;">
                <h2 style="color:#0b5fff; font-size:22px; font-weight:700; margin:0;">
                  ${msg("emailVerificationSubject")!"Verify your Wizbrand email"}
                </h2>
              </td>
            </tr>

            <tr>
              <td style="padding:20px 40px; font-size:15px; line-height:1.6; color:#444;">
                <p>Hello <strong>${user.username!user.email}</strong>,</p>
                <p>
                  Please verify your email for <strong>${realmName}</strong>. 
                  This link will expire in <strong>${(linkExpiration)!"a short time"}</strong>.
                </p>
              </td>
            </tr>

            <tr>
              <td align="center" style="padding:10px 40px 25px 40px;">
                <a href="${link}" style="background-color:#0b5fff; color:#fff; text-decoration:none; padding:12px 28px; border-radius:6px; display:inline-block; font-weight:600; font-size:15px;">Verify Email</a>
              </td>
            </tr>

            <tr>
              <td style="padding:0 40px 25px 40px; font-size:13px; line-height:1.6; color:#555;">
                <p>If the button doesnโ€™t work, copy this link:</p>
                <p style="word-break:break-all; color:#0b5fff;">${link}</p>
              </td>
            </tr>

            <tr>
              <td style="border-top:1px solid #e5e5e5;"></td>
            </tr>

            <tr>
              <td style="padding:20px 40px 30px 40px; font-size:12px; line-height:1.6; color:#777;">
                <p><strong>Wizbrand</strong></p>
                <p>${kcSanitize(msg("emailFooterHtml"))!"This is an automated email from Wizbrand. Please do not reply."}</p>
                <p>ยฉ ${.now?string("yyyy")} Wizbrand. All rights reserved.</p>
              </td>
            </tr>

          </table>
        </td>
      </tr>
    </table>

  </body>
</html>

B. Email Verification (Text)

File: themes/wizbrand-email/email/text/email-verification.ftl

${msg("emailVerificationSubject")!"Verify your Wizbrand email"}

Hello ${user.username!user.email},

Please verify your email for ${realmName}.
This link expires in ${(linkExpiration)!"a short time"}.

${link}

If you didnโ€™t request this, you can safely ignore this email.

Wizbrand
${kcSanitize(msg("emailFooterHtml"))!"This is an automated email from Wizbrand. Please do not reply."}
ยฉ ${.now?string("yyyy")} Wizbrand

C. Password Reset Template (HTML)

File: themes/wizbrand-email/email/html/password-reset.ftl

<!DOCTYPE html>
<html>
  <body style="margin:0;background:#f7f9fc;font-family:Arial,Helvetica,sans-serif;color:#333;">
    <div style="max-width:640px;margin:24px auto;background:#fff;border-radius:10px;padding:32px;">
      <div style="text-align:center;margin-bottom:20px;">
        <img src="https://www.wizbrand.com/images/logo.png" alt="Wizbrand" style="max-width:180px;height:auto;"/>
      </div>

      <h2 style="margin:0 0 12px;color:#0b5fff;text-align:center;">
        ${msg("passwordResetSubject")}
      </h2>

      <p>Hello <strong>${user.username!user.email}</strong>,</p>
      <p>We received a request to reset your Wizbrand account credentials.</p>
      <p>If this was you, click the button below. This link expires in <strong>${(linkExpiration)!"a short time"}</strong>.</p>

      <p style="text-align:center;margin:24px 0;">
        <a href="${link}" style="display:inline-block;text-decoration:none;padding:12px 22px;border-radius:6px;background:#0b5fff;color:#fff;font-weight:bold;">
          Reset credentials
        </a>
      </p>

      <p>If you didnโ€™t request this, you can safely ignore this email.</p>

      <hr style="border:none;border-top:1px solid #eee;margin:28px 0;"/>
      <div style="font-size:12px;color:#666;line-height:1.6;">
        <div><strong>${realmName}</strong></div>
        <div>${kcSanitize(msg("emailFooterHtml"))}</div>
        <div>ยฉ ${.now?string("yyyy")} Wizbrand</div>
      </div>
    </div>
  </body>
</html>

Step 7: Configure Email Settings in Keycloak Admin Console

  1. Go to Realm Settings โ†’ Email
  2. Enter SMTP details:
FieldExample
Hostsmtp.gmail.com / email-smtp.ap-south-1.amazonaws.com
Port587 (STARTTLS) or 465 (SSL)
Fromno-reply@wizbrand.com
From Display NameWizbrand Team
AuthenticationUsername/Password
Enable Debug SMTPโœ… (for testing)
  1. Click Test Connection
    If successful, youโ€™ll see a test email in your inbox.

Step 8: Troubleshooting Common Errors

ErrorCauseSolution
Template not found for nameFile missing or wrong folderMove it under email/html/ or email/text/
InvalidReferenceException: expiration missingUsed ${expiration} instead of ${linkExpiration}Replace with linkExpiration
Failed to send emailSMTP misconfigurationVerify port, auth, and TLS/SSL
535 Authentication failedWrong credentials or missing App PasswordUse Gmail App Password or SES credentials
PKIX path building failedUntrusted certificateAdd CA cert to JVM truststore
No email receivedSpam folder or unverified From addressVerify domain in SES / Mailgun

Step 9: Apply Theme and Test

  1. Go to Realm Settings โ†’ Themes
  2. Under Email Theme, select wizbrand-email
  3. Save changes
  4. Use Forgot Password or Verify Email to test

Step 10: Best Practices

  • Always provide both HTML and Text templates.
  • Keep all CSS inline for better compatibility.
  • Use absolute URLs for images (e.g., https://www.wizbrand.com/images/logo.png).
  • Use safe defaults for optional variables (e.g., ${(linkExpiration)!"a short time"}).
  • Add message bundles in /email/messages/messages_en.properties.
  • Disable template caching during development: bin/kc.sh start --spi-theme-cache-themes=false --spi-theme-cache-templates=false

Final Result

After completing these steps, your Keycloak emails will look like this:

Verification Email

  • Subject: โ€œVerify your Wizbrand emailโ€
  • Branded with Wizbrand logo and color scheme (#0b5fff)
  • Responsive on mobile and desktop
  • Clean layout with fallback link and footer

Password Reset Email

  • Subject: โ€œReset your Wizbrand credentialsโ€
  • Blue button with rounded edges
  • Expiry information and helpful footer

Bonus: Message Bundle Example

themes/wizbrand-email/email/messages/messages_en.properties

emailVerificationSubject=Verify your Wizbrand email
passwordResetSubject=Reset your Wizbrand credentials
emailFooterHtml=This is an automated email from Wizbrand. Please do not reply.

Summary

StepTaskKey Output
1Create themewizbrand-email
2Add theme.propertiesDefines inheritance
3Add email/html + email/textTemplates
4Replace ${expiration} โ†’ ${linkExpiration}Fix render errors
5Configure SMTPGmail / SES
6Apply ThemeRealm Settings โ†’ Themes
7Test ConnectionConfirm mail delivery
8Refine BrandingAdd logo, footer, color scheme

Conclusion

Youโ€™ve now built a fully branded Keycloak email system for Wizbrand with:

  • Custom logo and colors
  • Fully responsive, professional HTML templates
  • Secure and working SMTP integration
  • Safe, bug-free FreeMarker logic
  • Localization-ready message bundles

Your users will now receive elegant, trustworthy, and brand-consistent emails that match Wizbrandโ€™s identity โ€” improving user experience and trust.


Post Views: 2,209
  • Email Templates
  • How to Customize and Brand Keycloak Email
  • Keycloak
  • Keycloak Email
  • Keycloak Email Templates
Subscribe
Login
Notify of
guest
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
  • Linux Server Diagnostic Commands: Complete Guide for Performance, Network & System Troubleshooting
  • The Ultimate Guide to CDOM โ€“ Certified DataOps Manager Certification
  • The Practical Path to AI Reliability: A Guide to the Certified MLOps Manager
  • Master the Machine Learning Lifecycle:Guide to Becoming a Certified MLOps Architect
  • How to Build a Project-Level AI Memory System That Works Across Codex, Claude, and Other AI Coding Tools
  • Certified MLOps Professional: A Deep Dive into the Certified MLOps Professional Certification
  • Certified MLOps Engineer : The Comprehensive Guide to Mastering Machine Learning Operations
  • Codex vs Claude: A Complete Practical Guide for Modern Developers (2026)
  • Certified AIOps Professional Program A Guide to Career Growth
  • Keycloak Multi-Client Architecture with Project-Based Email Validation (Student, Trainer, Company, Consulting)
  • Incorrect definition of table mysql.column_stats
  • Mautic and PHP 8.3 Compatibility Guide (2026)
  • Certified AIOps Engineer: The Complete Career Path and Certification Guide
  • How to Rename Apache Virtual Host Files Safely (Step-by-Step Guide for Linux)
  • AIOps Foundation Certification: Everything You Need to Know to Get Certified
  • DevOps to Certified Site Reliability Professional: A Senior Mentorโ€™s Guide
  • Certified Site Reliability Manager Training, Preparation, and Career Mapping
  • Certified Site Reliability Architect: The Complete Career Guide
  • What Is a VPN? A Complete Beginner-to-Advanced Tutorial
  • How to Install, Secure, and Tune MySQL 8.4 on Ubuntu 24.04 for Apache Event MPM and PHP-FPM
  • Complete Guide to Certified Site Reliability Engineer Career
  • Certified DevSecOps Professional Step by Step
  • Certified DevSecOps Manager: Complete Career Guide
  • Certified DevSecOps Engineer: Skills, Career Path and Certification Guide
  • Step-by-Step: Become a Certified DevSecOps Architect
  • Tuning PHP 8.3 for Apache Event MPM and PHP-FPM on Ubuntu: A Complete Step-by-Step Production Guide
  • Complete Step-by-Step Guide to Configure Apache Event MPM, Create index.php, Set Up VirtualHost, and Fix Ubuntu Default Page
  • Convert XAMPP Apache to Event MPM + System PHP-FPM
  • The Gateway to System Observability Engineering (MOE)
  • How to Finetune Apache and Prove It Works: A Real-World Guide to Testing Performance, Concurrency, HTTP/2, Memory, CPU, and Security

Recent Comments

  1. emmy day on SQLSTATE[42S22]: Column not found: 1054 Unknown column ‘provider’ in ‘field list’
  2. digital banking on Complete Tutorial: Setting Up Laravel Telescope Correctly (Windows + XAMPP + Custom Domain)
  3. SAHIL DHINGRA on How to Uninstall Xampp from your machine when it is not visible in Control panel programs & Feature ?
  4. Abhishek on MySQL: List of Comprehensive List of approach to secure MySQL servers.
  5. Kristina on Best practices to followed in .httacess to avoid DDOS attack?

Archives

  • April 2026
  • March 2026
  • February 2026
  • January 2026
  • December 2025
  • November 2025
  • October 2025
  • September 2025
  • August 2025
  • July 2025
  • June 2025
  • May 2025
  • April 2025
  • March 2025
  • February 2025
  • January 2025
  • December 2024
  • November 2024
  • October 2024
  • September 2024
  • August 2024
  • July 2024
  • June 2024
  • May 2024
  • April 2024
  • March 2024
  • February 2024
  • January 2024
  • December 2023
  • November 2023
  • October 2023
  • September 2023
  • August 2023
  • July 2023
  • May 2023
  • April 2023
  • March 2023
  • February 2023
  • January 2023
  • December 2022

Categories

  • Ai
  • AI Blogging
  • AiOps
  • ajax
  • Android Studio
  • Antimalware
  • Antivirus
  • Apache
  • Api
  • API Security
  • Api Testing
  • APK
  • Aws
  • Bike Rental Services
  • ChatGPT
  • Code Linting
  • Composer
  • cPanel
  • Cyber Threat Intelligence
  • Cybersecurity
  • Data Loss Prevention
  • Database
  • dataops
  • Deception Technology
  • DeepSeek
  • Devops
  • DevSecOps
  • DevTools
  • Digital Asset Management
  • Digital Certificates
  • Docker
  • Drupal
  • emulator
  • Encryption Tools
  • Endpoint Security Tools
  • Error
  • facebook
  • Firewalls
  • Flutter
  • git
  • GITHUB
  • Google Antigravity
  • Google play console
  • Google reCAPTCHA
  • Gradle
  • Guest posting
  • health and fitness
  • IDE
  • Identity and Access Management
  • Incident Response
  • Instagram
  • Intrusion Detection and Prevention Systems
  • jobs
  • Joomla
  • Keycloak
  • Laravel
  • Law News
  • Lawyer Discussion
  • Legal Advice
  • Linkedin
  • Linkedin Api
  • Linux
  • Livewire
  • Mautic
  • Medical Tourism
  • MlOps
  • MobaXterm
  • Mobile Device Management
  • Multi-Factor Authentication
  • MySql
  • Network Traffic Analysis tools
  • Paytm
  • Penetration Testing
  • php
  • PHPMyAdmin
  • Pinterest Api
  • Quora
  • SAST
  • SecOps
  • Secure File Transfer Protocol
  • Security Analytics Tools
  • Security Auditing Tools
  • Security Information and Event Management
  • Seo
  • Server Management Tools
  • Single Sign-On
  • Site Reliability Engineering
  • soft 404
  • software
  • SuiteCRM
  • SysOps
  • Threat Model
  • Twitter
  • Twitter Api
  • ubuntu
  • Uncategorized
  • Virtual Host
  • Virtual Private Networks
  • VPNs
  • Vulnerability Assessment Tools
  • Web Application Firewalls
  • Windows Processor
  • Wordpress
  • WSL (Windows Subsystem for Linux)
  • X.com
  • Xampp
  • Youtube
©2026 DevSecOps Now!!! | WordPress Theme: EcoCoded
wpDiscuz