Support custom email templates in multiple languages via Management API
Introduce localized email template customization capabilities. This update allows administrators to create and manage multiple email templates for different languages and template types (e.g., SignIn, ForgotPassword) via the management API.
Email connectors now support automatic template selection based on the user's preferred language. If a template is not available in the user's preferred language, the default template will be used.
- For client-side API requests, like experience API and user account API, the user's preferred language is determined by the
Accept-Language
header. - For server-side API requests, like organization invitation API, email language preference can be set by passing extra
locale
parameter in themessagePayload
. - The email template selection logic is based on the following priority order:
- Find the template that matches the user's preferred language detected from the request.
- Find the template that matches the default language set in the sign-in experience settings.
- Use the default template set in the email connector settings.
Management API
PUT /email-templates
: Bulk create or update email templates.GET /email-templates
: List all email templates with filter by language and type support.DELETE /email-templates
: Bulk delete email templates by language and type.GET /email-templates/{id}
: Get a specific email template by ID.DELETE /email-templates/{id}
: Delete a specific email template by ID.PATCH /email-templates/{id}/details
: Update email template details by ID.
Supported email connectors
@logto/connector-aliyun-dm
@logto/connector-aws-ses
@logto/connector-mailgun
@logto/connector-sendgrid-email
@logto/connector-smtp
Unsupported email connectors
The following email connectors have their templates managed at the provider side and do not support reading templates from Logto.
The user's preferred language will be passed to the provider as the locale
parameter in the email sending request payload. For i18n support, administrators must manage the template selection logic at the provider side.
@logto/connector-postmark
@logto/connector-http-email
Pass additional context variables to email templates
Enhanced email template customization by introducing additional context variables that developers can utilize in message templates. These new variables provide deeper contextual information about the authentication workflow, enabling more personalized and scenario-specific email content.
user
:UserInfo
- Contains basic user profile data (name, primaryEmail, etc.) for personalizationapplication
:ApplicationInfo
- Contains basic application-specific data (name, logo, etc.) for personalizationorganization
:OrganizationInfo
- Contains basic organization-specific data (name, logo, etc.) for personalizationinviter
:UserInfo
- Contains basic inviter profile data (name, primaryEmail, etc.) for personalization
usageType | Scenario | Variables |
---|---|---|
SignIn | Users sign in using their email and verify by entering verification code instead of entering a password. | code: string application: ApplicationInfo organization?: OrganizationInfo
|
Register | Users create an account using their email and verify it by entering a verification code sent by Logto to their email. | code: string application: ApplicationInfo organization?: OrganizationInfo
|
ForgotPassword | If users forget their password during login, they can choose to verify their identity using the email they've already verified with Logto. | code: string application: ApplicationInfo organization?: OrganizationInfo
|
Generic | This template can be used as a general backup option for various scenarios, including testing connector configurations and so on. | code: string |
OrganizationInvitation | Use this template to send users an invitation link to join the organization. | link: string organization: OrganizationInfo inviter?: UserInfo
|
UserPermissionValidation | During app usage, there may be some high-risk operations or operations with a relatively high risk level that require additional user verification, such as bank transfers, deleting resources in use, and canceling memberships. The UserPermissionValidation template can be used to define the content of the email verification code users receive in these situations.
| code: string user: UserInfo application?: ApplicationInfo
|
BindNewIdentifier | When a user modifies their profile, they may bind an email address to their current account. In this case, the BindNewIdentifier template can be used to customize the content of the verification email.
| code: string user: UserInfo application?: ApplicationInfo
|
Check Email templates for more information on how to use these new context variables in your email templates.
Improvements
-
1c7bdf9ba: add legacy password type supporting custom hasing function, credits @fre2d0m
You can now set the type of
password_encryption_method
tolegacy
, and store info with a JSON string format (containing a hash algorithm, arguments, and an encrypted password) in thepassword_encrypted
field. By doing this, you can use any hash algorithm supported by Node.js, this is useful when migrating from other password hash algorithms, especially for the ones that include salt.The format of the JSON string is as follows:
["hash_algorithm", ["argument1", "argument2", ...], "expected_hashed_value"]
And you can use
@
as the input password in the arguments.For example, if you are using SHA256 with a salt, you can store the password in the following format:
[ "sha256", ["salt123", "@"], "c465f66c6ac481a7a17e9ed5b4e2e7e7288d892f12bf1c95c140901e9a70436e" ]
Then when the user uses the password (
password123
), thelegacyVerify
function will use thesha256
algorithm with thesalt123
and the input password to verify the password.In this case,
salt123
is the first argument,@
is the input password, then the following code will be executed:const hash = crypto.createHash("sha256"); hash.update("salt123" + "password123"); const expectedHashedValue = hash.digest("hex");
-
b0135bcd3: enhanced handlebars template processing in the connector to support nested property access in email template variables
Updates
- Updated
replaceSendMessageHandlebars
logic to handle nested property paths in template variables - Latest template processing logic now supports:
- Direct replacement of primitive values (string/number/null/undefined)
- Deep property access using dot-notation (e.g.,
organization.branding.logoUrl
) - Graceful handling of missing properties (replaces with empty string)
- Preservation of original handlebars when variables aren't provided in payload
Examples
- Direct replacement
replaceSendMessageKeysWithPayload("Your verification code is {{code}}", { code: "123456", }); // 'Your verification code is 123456'
- Deep property access
replaceSendMessageKeysWithPayload( "Your logo is {{organization.branding.logoUrl}}", { organization: { branding: { logoUrl: "https://example.com/logo.png" } } } ); // 'Your logo is https://example.com/logo.png'
- Missing properties
replaceSendMessageKeysWithPayload( "Your logo is {{organization.branding.logoUrl}}", { organization: { name: "foo" } } ); // 'Your logo is '
- Preservation of missing variables
replaceSendMessageKeysWithPayload( "Your application is {{application.name}}", {} ); // 'Your application is {{application.name}}'
- Updated
-
c87424025: support role names alongside role IDs in organization user role assignment/replacement with merge capability
This update enhances organization user role management APIs to support role assignment by both names and IDs, improving integration flexibility.
- Added
organizationRoleNames
parameter to:- POST
/api/organizations/{id}/users/{userId}/roles
(assign roles) - PUT
/api/organizations/{id}/users/{userId}/roles
(replace roles)
- POST
- Make both
organizationRoleNames
andorganizationRoleIds
optional in the above APIs- If both are not provided, or empty, an invalid data error will be thrown
- Merge logic when both parameters are provided:
- Combines roles from
organizationRoleNames
andorganizationRoleIds
- Automatically deduplicates entries
- Validates all names/IDs exist before applying changes
- Combines roles from
- Maintains backward compatibility with existing integrations using role IDs
- Added
Fixes
-
edeb7cc8d: add
AuthnStatement
to SAML app assertion response -
b2a77d79c: add
strictPhoneRegionNumberCheck
to config with default valuefalse
When this configuration is enabled, the connector will assume by default that all phone numbers include a valid region code and rely on this to determine whether the phone number belongs to mainland China. If your users' phone numbers do not include a region code due to historical reasons, their sign-in processes may be affected. Please enable this setting with caution.
-
20b61e05e: adjust TOTP secret length to 20 bytes
Update the TOTP secret generation to use 20 bytes (160 bits), following the recommendation in RFC 6238 (TOTP) and RFC 4226 (HOTP).
This aligns with the standard secret length used by most 2FA applications and provides better security while maintaining compatibility with existing TOTP validators.
Reference:
- RFC 6238 (TOTP) Section 5.1: https://www.rfc-editor.org/rfc/rfc6238#section-5.1
- RFC 4226 (HOTP) Section 4, Requirement 6: https://www.rfc-editor.org/rfc/rfc4226#section-4
-
f15602f19: incorrect pagination behavior in organization role scopes APIs
- Fix
/api/organization-roles/{id}/scopes
and/api/organization-roles/{id}/resource-scopes
endpoints to:- Return all scopes when no pagination parameters are provided
- Support optional pagination when query parameters are present
- Fix Console to properly display all organization role scopes on the organization template page
- Fix