diff --git a/docs/configuration/notifier/index.md b/docs/configuration/notifier/index.md
index f48a2d702..df6a37488 100644
--- a/docs/configuration/notifier/index.md
+++ b/docs/configuration/notifier/index.md
@@ -47,41 +47,46 @@ required: no
{: .label .label-config .label-green }
-This option allows the administrator to set custom templates for notifications
-the templates folder should contain the following files
+This option allows the administrator to set a path where custom templates for notifications can be found. Each template
+has two extensions; `.html` for HTML templates, and `.txt` for plaintext templates.
-|File |Description |
-|------------------------|---------------------------------------------------|
-|PasswordResetStep1.html |HTML Template for Step 1 of password reset process |
-|PasswordResetStep1.txt |Text Template for Step 1 of password reset process |
-|PasswordResetStep2.html |HTML Template for Step 2 of password reset process |
-|PasswordResetStep2.txt |Text Template for Step 2 of password reset process |
+| Template | Description |
+|:--------------------:|:-----------------------------------------------------------------------------------------------:|
+| IdentityVerification | Template used when registering devices or resetting passwords |
+| PasswordReset | Template used to send the notification to users when their password has successfully been reset |
-Note:
-* if you don't define some of these files, a default template is used for that notification
+For example, to modify the `IdentityVerification` HTML template, if your `template_path` was `/config/email_templates`,
+you would create the `/config/email_templates/IdentityVerification.html` file.
+
+_**Note:** you may configure this directory and add only add the templates you wish to override, any templates not
+supplied in this folder will utilize the default templates._
In template files, you can use the following variables:
-|File |Description |
-|------------------------|---------------------------------------------------|
-|`{{.title}}`| A predefined title for the email.
It will be `"Reset your password"` or `"Password changed successfully"`, depending on the current step |
-|`{{.url}}` | The url that allows to reset the user password |
-|`{{.displayName}}` |The name of the user, i.e. `John Doe` |
-|`{{.button}}` |The content for the password reset button, it's hardcoded to `Reset` |
-|`{{.remoteIP}}` |The remote IP address that initiated the request or event |
+| Placeholder | Templates | Description |
+|:--------------------:|:--------------------:|:---------------------------------------------------------------------------------------------------------------------------------------------:|
+| `{{ .LinkURL }}` | IdentityVerification | The URL of the used with the IdentityVerification template. |
+| `{{ .LinkText }}` | IdentityVerification | The display value for the IdentityVerification button intended for the link. |
+| `{{ .Title }}` | All | A predefined title for the email.
It will be `"Reset your password"` or `"Password changed successfully"`, depending on the current step |
+| `{{ .DisplayName }}` | All | The name of the user, i.e. `John Doe` |
+| `{{ .RemoteIP }}` | All | The remote IP address that initiated the request or event |
-#### Example
+#### Examples
+
+This is a basic example:
```html
- {{.title}}
- Hi {{.displayName}}
- This email has been sent to you in order to validate your identity
- Click here to change your password
+ {{ .Title }}
+ Hi {{ .DisplayName }}
+ This email has been sent to you in order to validate your identity.
+ Click here to change your password.
```
+Some Additional examples for specific purposes can be found in the
+[examples directory on GitHub](https://github.com/authelia/authelia/tree/master/examples/templates/notifications).
### filesystem
diff --git a/examples/templates/notifications/README.md b/examples/templates/notifications/README.md
new file mode 100644
index 000000000..115332a51
--- /dev/null
+++ b/examples/templates/notifications/README.md
@@ -0,0 +1,4 @@
+# Notification Templates
+
+The following folder contains email templates as examples of what can be done with the email template system. See the
+[docs](https://www.authelia.com/docs/configuration/notifier/#template_path) for more information.
\ No newline at end of file
diff --git a/examples/templates/notifications/html_email_with_button_and_link.html b/examples/templates/notifications/html_email_with_button_and_link.html
new file mode 100644
index 000000000..e5f764486
--- /dev/null
+++ b/examples/templates/notifications/html_email_with_button_and_link.html
@@ -0,0 +1,430 @@
+
+
+
+
+
+
+ Authelia
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+ {{ .Title }}
+ |
+
+
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+ |
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+ Hi {{ .DisplayName }}
+ |
+
+
+
+ This email has been sent to you in order to validate your identity.
+ If you did not initiate the process your credentials might have been compromised. You should reset your password and contact an administrator.
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+ {{ .LinkText }}
+ |
+
+
+
+
+ |
+
+
+
+
+ {{ .LinkURL }}
+ |
+
+
+
+
+ |
+
+
+
+ |
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Please contact an administrator if you did not initiate this process.
+ |
+
+
+
+
+ |
+
+
+
+
+ This email was generated by a request from the IP address {{ .RemoteIP }}.
+ |
+
+
+
+ |
+
+
+
+
+ |
+
+
+
+ |
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/internal/configuration/validator/notifier.go b/internal/configuration/validator/notifier.go
index 45216fa92..56810a60d 100644
--- a/internal/configuration/validator/notifier.go
+++ b/internal/configuration/validator/notifier.go
@@ -56,28 +56,28 @@ func validateNotifierTemplates(config *schema.NotifierConfiguration, validator *
return
}
- if t, err = template.ParseFiles(filepath.Join(config.TemplatePath, templates.TemplateNameStep1+".html")); err == nil {
- templates.HTMLEmailTemplateStep1 = t
+ if t, err = template.ParseFiles(filepath.Join(config.TemplatePath, templates.TemplateNameIdentityVerification+".html")); err == nil {
+ templates.EmailIdentityVerificationHTML = t
} else {
- validator.PushWarning(fmt.Errorf(errFmtNotifierTemplateLoad, templates.TemplateNameStep1+".html", err))
+ validator.PushWarning(fmt.Errorf(errFmtNotifierTemplateLoad, templates.TemplateNameIdentityVerification+".html", err))
}
- if t, err = template.ParseFiles(filepath.Join(config.TemplatePath, templates.TemplateNameStep1+".txt")); err == nil {
- templates.PlainTextEmailTemplateStep1 = t
+ if t, err = template.ParseFiles(filepath.Join(config.TemplatePath, templates.TemplateNameIdentityVerification+".txt")); err == nil {
+ templates.EmailIdentityVerificationPlainText = t
} else {
- validator.PushWarning(fmt.Errorf(errFmtNotifierTemplateLoad, templates.TemplateNameStep1+".txt", err))
+ validator.PushWarning(fmt.Errorf(errFmtNotifierTemplateLoad, templates.TemplateNameIdentityVerification+".txt", err))
}
- if t, err = template.ParseFiles(filepath.Join(config.TemplatePath, templates.TemplateNameStep2+".html")); err == nil {
- templates.HTMLEmailTemplateStep2 = t
+ if t, err = template.ParseFiles(filepath.Join(config.TemplatePath, templates.TemplateNameBasic+".html")); err == nil {
+ templates.EmailPasswordResetHTML = t
} else {
- validator.PushWarning(fmt.Errorf(errFmtNotifierTemplateLoad, templates.TemplateNameStep2+".html", err))
+ validator.PushWarning(fmt.Errorf(errFmtNotifierTemplateLoad, templates.TemplateNameBasic+".html", err))
}
- if t, err = template.ParseFiles(filepath.Join(config.TemplatePath, templates.TemplateNameStep2+".txt")); err == nil {
- templates.PlainTextEmailTemplateStep2 = t
+ if t, err = template.ParseFiles(filepath.Join(config.TemplatePath, templates.TemplateNameBasic+".txt")); err == nil {
+ templates.EmailPasswordResetPlainText = t
} else {
- validator.PushWarning(fmt.Errorf(errFmtNotifierTemplateLoad, templates.TemplateNameStep2+".txt", err))
+ validator.PushWarning(fmt.Errorf(errFmtNotifierTemplateLoad, templates.TemplateNameBasic+".txt", err))
}
}
diff --git a/internal/handlers/handler_reset_password_step2.go b/internal/handlers/handler_reset_password_step2.go
index 19e3d5c89..7950f7b07 100644
--- a/internal/handlers/handler_reset_password_step2.go
+++ b/internal/handlers/handler_reset_password_step2.go
@@ -86,12 +86,12 @@ func ResetPasswordPost(ctx *middlewares.AutheliaCtx) {
if !disableHTML {
htmlParams := map[string]interface{}{
- "title": "Password changed successfully",
- "displayName": userInfo.DisplayName,
- "remoteIP": ctx.RemoteIP().String(),
+ "Title": "Password changed successfully",
+ "DisplayName": userInfo.DisplayName,
+ "RemoteIP": ctx.RemoteIP().String(),
}
- err = templates.HTMLEmailTemplateStep2.Execute(bufHTML, htmlParams)
+ err = templates.EmailPasswordResetHTML.Execute(bufHTML, htmlParams)
if err != nil {
ctx.Logger.Error(err)
@@ -103,10 +103,10 @@ func ResetPasswordPost(ctx *middlewares.AutheliaCtx) {
bufText := new(bytes.Buffer)
textParams := map[string]interface{}{
- "displayName": userInfo.DisplayName,
+ "DisplayName": userInfo.DisplayName,
}
- err = templates.PlainTextEmailTemplateStep2.Execute(bufText, textParams)
+ err = templates.EmailPasswordResetPlainText.Execute(bufText, textParams)
if err != nil {
ctx.Logger.Error(err)
diff --git a/internal/middlewares/identity_verification.go b/internal/middlewares/identity_verification.go
index 13d8f3498..db6c7076d 100644
--- a/internal/middlewares/identity_verification.go
+++ b/internal/middlewares/identity_verification.go
@@ -79,14 +79,14 @@ func IdentityVerificationStart(args IdentityVerificationStartArgs, delayFunc Tim
if !disableHTML {
htmlParams := map[string]interface{}{
- "title": args.MailTitle,
- "url": link,
- "button": args.MailButtonContent,
- "displayName": identity.DisplayName,
- "remoteIP": ctx.RemoteIP().String(),
+ "Title": args.MailTitle,
+ "LinkURL": link,
+ "LinkText": args.MailButtonContent,
+ "DisplayName": identity.DisplayName,
+ "RemoteIP": ctx.RemoteIP().String(),
}
- err = templates.HTMLEmailTemplateStep1.Execute(bufHTML, htmlParams)
+ err = templates.EmailIdentityVerificationHTML.Execute(bufHTML, htmlParams)
if err != nil {
ctx.Error(err, messageOperationFailed)
@@ -96,11 +96,11 @@ func IdentityVerificationStart(args IdentityVerificationStartArgs, delayFunc Tim
bufText := new(bytes.Buffer)
textParams := map[string]interface{}{
- "url": link,
- "displayName": identity.DisplayName,
+ "LinkURL": link,
+ "DisplayName": identity.DisplayName,
}
- err = templates.PlainTextEmailTemplateStep1.Execute(bufText, textParams)
+ err = templates.EmailIdentityVerificationPlainText.Execute(bufText, textParams)
if err != nil {
ctx.Error(err, messageOperationFailed)
diff --git a/internal/templates/const.go b/internal/templates/const.go
index edaea45b2..4c15720ce 100644
--- a/internal/templates/const.go
+++ b/internal/templates/const.go
@@ -2,6 +2,6 @@ package templates
// Template File Names.
const (
- TemplateNameStep1 = "PasswordResetStep1"
- TemplateNameStep2 = "PasswordResetStep2"
+ TemplateNameBasic = "Basic"
+ TemplateNameIdentityVerification = "IdentityVerification"
)
diff --git a/internal/templates/html_email_step_1.go b/internal/templates/email_identity_verification_html.go
similarity index 90%
rename from internal/templates/html_email_step_1.go
rename to internal/templates/email_identity_verification_html.go
index ea18fe180..01aac0f33 100644
--- a/internal/templates/html_email_step_1.go
+++ b/internal/templates/email_identity_verification_html.go
@@ -4,19 +4,19 @@ import (
"text/template"
)
-// HTMLEmailTemplateStep1 the template of email that the user will receive for identity verification.
-var HTMLEmailTemplateStep1 *template.Template
+// EmailIdentityVerificationHTML the template of email that the user will receive for identity verification.
+var EmailIdentityVerificationHTML *template.Template
func init() {
- t, err := template.New("html_email_template").Parse(emailHTMLContentStep1)
+ t, err := template.New("email_identity_verification_html").Parse(emailContentIdentityVerificationHTML)
if err != nil {
panic(err)
}
- HTMLEmailTemplateStep1 = t
+ EmailIdentityVerificationHTML = t
}
-const emailHTMLContentStep1 = `
+const emailContentIdentityVerificationHTML = `
@@ -244,7 +244,7 @@ const emailHTMLContentStep1 = `
- {{.title}}
+ {{ .Title }}
|
@@ -317,7 +317,7 @@ const emailHTMLContentStep1 = `
- Hi {{.displayName}}
+ Hi {{ .DisplayName }}
|
@@ -339,19 +339,7 @@ const emailHTMLContentStep1 = `
- {{.button}}
- |
-
-
-
-
- |
-
-
-
-
- {{.url}}
+ {{ .LinkText }}
|
@@ -412,7 +400,7 @@ const emailHTMLContentStep1 = `
- Please contact an administrator if you did not initiate the process.
+ Please contact an administrator if you did not initiate this process.
|
@@ -425,7 +413,7 @@ const emailHTMLContentStep1 = `
- This email was generated by some with the IP address {{.remoteIP}}.
+ This email was generated by a request from the IP address {{ .RemoteIP }}.
|
diff --git a/internal/templates/email_identity_verification_plaintext.go b/internal/templates/email_identity_verification_plaintext.go
new file mode 100644
index 000000000..5af344a41
--- /dev/null
+++ b/internal/templates/email_identity_verification_plaintext.go
@@ -0,0 +1,28 @@
+package templates
+
+import (
+ "text/template"
+)
+
+// EmailIdentityVerificationPlainText the template of email that the user will receive for identity verification.
+var EmailIdentityVerificationPlainText *template.Template
+
+func init() {
+ t, err := template.New("email_identity_verification_plain_text").Parse(emailContentIdentityVerificationPlainText)
+ if err != nil {
+ panic(err)
+ }
+
+ EmailIdentityVerificationPlainText = t
+}
+
+const emailContentIdentityVerificationPlainText = `
+This email has been sent to you in order to validate your identity.
+If you did not initiate the process your credentials might have been compromised. You should reset your password and contact an administrator.
+
+To setup your 2FA please visit the following URL: {{ .LinkURL }}
+
+This email was generated by a user with the IP {{ .RemoteIP }}.
+
+Please contact an administrator if you did not initiate this process.
+`
diff --git a/internal/templates/html_email_step_2.go b/internal/templates/email_password_reset_html.go
similarity index 95%
rename from internal/templates/html_email_step_2.go
rename to internal/templates/email_password_reset_html.go
index ba3e4b5bd..f6f2d5c81 100644
--- a/internal/templates/html_email_step_2.go
+++ b/internal/templates/email_password_reset_html.go
@@ -4,19 +4,20 @@ import (
"text/template"
)
-// HTMLEmailTemplateStep2 the template of email that the user will receive for identity verification.
-var HTMLEmailTemplateStep2 *template.Template
+// EmailPasswordResetHTML the template of email that the user will receive for identity verification.
+var EmailPasswordResetHTML *template.Template
func init() {
- t, err := template.New("html_email_template").Parse(emailHTMLContentStep2)
+ t, err := template.New("email_password_reset_html").Parse(emailContentPasswordResetHTML)
if err != nil {
panic(err)
}
- HTMLEmailTemplateStep2 = t
+ EmailPasswordResetHTML = t
}
-const emailHTMLContentStep2 = `
+//nolint:gosec // This is a template not hardcoded credentials.
+const emailContentPasswordResetHTML = `
@@ -242,7 +243,7 @@ const emailHTMLContentStep2 = `
- {{.title}}
+ {{ .Title }}
|
@@ -315,7 +316,7 @@ const emailHTMLContentStep2 = `
- Hi {{.displayName}}
+ Hi {{ .DisplayName }}
Your password has been successfully reset.
If you did not initiate the process your credentials might have been compromised. You should reset your password and contact an administrator.
|
@@ -385,7 +386,7 @@ const emailHTMLContentStep2 = `
- Please contact an administrator if you did not initiate the process.
+ Please contact an administrator if you did not initiate this process.
|
@@ -398,7 +399,7 @@ const emailHTMLContentStep2 = `
- This email was generated by some with the IP address {{.remoteIP}}.
+ This email was generated by a request from the IP address {{ .RemoteIP }}.
|
diff --git a/internal/templates/email_password_reset_plaintext.go b/internal/templates/email_password_reset_plaintext.go
new file mode 100644
index 000000000..0f4b0078a
--- /dev/null
+++ b/internal/templates/email_password_reset_plaintext.go
@@ -0,0 +1,26 @@
+package templates
+
+import (
+ "text/template"
+)
+
+// EmailPasswordResetPlainText the template of email that the user will receive for identity verification.
+var EmailPasswordResetPlainText *template.Template
+
+func init() {
+ t, err := template.New("email_password_reset_plain_text").Parse(emailContentBasicPlainText)
+ if err != nil {
+ panic(err)
+ }
+
+ EmailPasswordResetPlainText = t
+}
+
+const emailContentBasicPlainText = `
+Your password has been successfully reset.
+If you did not initiate the process your credentials might have been compromised. You should reset your password and contact an administrator.
+
+This email was generated by a user with the IP {{ .RemoteIP }}.
+
+Please contact an administrator if you did not initiate this process.
+`
diff --git a/internal/templates/plaintext_email_step_1.go b/internal/templates/plaintext_email_step_1.go
deleted file mode 100644
index 22ffbd6bc..000000000
--- a/internal/templates/plaintext_email_step_1.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package templates
-
-import (
- "text/template"
-)
-
-// PlainTextEmailTemplateStep1 the template of email that the user will receive for identity verification.
-var PlainTextEmailTemplateStep1 *template.Template
-
-func init() {
- t, err := template.New("text_email_template").Parse(emailPlainTextContentStep1)
- if err != nil {
- panic(err)
- }
-
- PlainTextEmailTemplateStep1 = t
-}
-
-const emailPlainTextContentStep1 = `
-This email has been sent to you in order to validate your identity.
-If you did not initiate the process your credentials might have been compromised. You should reset your password and contact an administrator.
-
-To setup your 2FA please visit the following URL: {{.url}}
-
-This email was generated by a user with the IP {{.remoteIP}}.
-
-Please contact an administrator if you did not initiate the process.
-`
diff --git a/internal/templates/plaintext_email_step_2.go b/internal/templates/plaintext_email_step_2.go
deleted file mode 100644
index c378d81cf..000000000
--- a/internal/templates/plaintext_email_step_2.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package templates
-
-import (
- "text/template"
-)
-
-// PlainTextEmailTemplateStep2 the template of email that the user will receive for identity verification.
-var PlainTextEmailTemplateStep2 *template.Template
-
-func init() {
- t, err := template.New("text_email_template").Parse(emailPlainTextContentStep2)
- if err != nil {
- panic(err)
- }
-
- PlainTextEmailTemplateStep2 = t
-}
-
-const emailPlainTextContentStep2 = `
-Your password has been successfully reset.
-If you did not initiate the process your credentials might have been compromised. You should reset your password and contact an administrator.
-
-This email was generated by a user with the IP {{.remoteIP}}.
-
-Please contact an administrator if you did not initiate the process.
-`