AWS Cognito自定义消息触发器异常:邮件模板未生效求助
问题描述
实现用户更新邮箱后发送验证邮件功能,使用AWS Lambda的CustomMessageTriggerHandler触发器,代码如下:
import { CustomMessageTriggerHandler } from 'aws-lambda'; const verifyEmailTemplate = (name: string, linkParameter: string): string => { const nameWrapper = name ? ` ${name}` : ''; const body = ` <h2> Please verify your email </h2> <p> Hi${nameWrapper} </p> <div> <a href="${linkParameter}">CLICK HERE TO VERIFY YOUR EMAIL</a> </div> `; return body; }; export const handler: CustomMessageTriggerHandler = async (event) => { console.debug('event: ', event); try { const { ENVIRONMENT } = process.env; const email = ENVIRONMENT === 'local' ? null : event.request.userAttributes.email; const name = ENVIRONMENT === 'local' ? '' : event.request.userAttributes.name; const code = event.request.codeParameter; const linkParameter = event.request.linkParameter; if ( event.triggerSource === 'CustomMessage_UpdateUserAttribute' && event.request.userAttributes.email_verified !== 'true' ) { console.debug('CustomMessage_UpdateUserAttribute'); event.response = { emailSubject: 'Your account updates needs to be verified', emailMessage: verifyEmailTemplate(name, linkParameter), smsMessage: `test`, }; } return event; } catch (error) { } };
实际发送的邮件标题符合自定义设置,但内容未使用模板,而是默认验证码模板:
Please verify your email Thanks for signing up, to complete your registration please verify your e-mail address 473080
用户池配置:
- 「注册体验」→「编辑属性验证和用户账户确认」设置为「若有可用手机号则发送SMS,否则发送邮件」
- 未启用预设消息模板
触发事件数据:
{ "version": "1", "region": "us-east-1", "userPoolId": "us-east-1_d", "userName": "3448e458", "callerContext": { "awsSdkVersion": "aws-sdk-js-3.670.0", "clientId": "6cac2thnduoep1o9n8rjfhnifi" }, "triggerSource": "CustomMessage_UpdateUserAttribute", "request": { "userAttributes": { "sub": "3448e458", "email_verified": "false", "cognito:user_status": "CONFIRMED", "custom:staged_email": "noise@gmail.com", "phone_number_verified": "true", "phone_number": "+14133248551", "given_name": "John", "family_name": "Doe", "email": "jdoe13@icloud.com" }, "codeParameter": "{####}", "linkParameter": "{##Click Here##}", "usernameParameter": null }, "response": { "smsMessage": null, "emailMessage": null, "emailSubject": null } }
排查分析与解决方案
核心问题点
用户属性
name不存在
代码中尝试获取event.request.userAttributes.name,但事件数据中仅存在given_name和family_name字段,导致name为undefined,虽不直接导致模板失效,但可能引发渲染异常。HTML模板转义错误
模板中使用<h2>这类HTML实体转义字符,而非直接的HTML标签,若Cognito配置为HTML邮件模式,这些字符会被当作纯文本显示,而非渲染为格式元素。验证方式占位符不匹配
用户池当前使用验证码验证模式(codeParameter存在{####}占位符),但自定义模板仅使用了链接验证的linkParameter,未包含{####}。Cognito无法找到验证码占位符时,会自动回退到默认模板发送。异常处理缺失
Lambda的catch块为空,无法捕获和记录模板生成过程中的错误,可能导致event.response未被正确返回。
修复步骤
修正用户属性获取逻辑
改为从given_name和family_name拼接用户名:const name = ENVIRONMENT === 'local' ? '' : `${event.request.userAttributes.given_name} ${event.request.userAttributes.family_name}`.trim();修复HTML模板转义
直接使用原生HTML标签,无需转义(Cognito支持HTML格式邮件):const verifyEmailTemplate = (name: string, linkParameter: string): string => { const nameWrapper = name ? ` ${name}` : ''; const body = ` <h2>Please verify your email</h2> <p>Hi${nameWrapper}</p> <div><a href="${linkParameter}">CLICK HERE TO VERIFY YOUR EMAIL</a></div> `; return body; };匹配验证方式的占位符
- 若使用链接验证:在用户池「属性验证」设置中切换为链接模式,确保模板保留
linkParameter占位符。 - 若使用验证码验证:在模板中添加
{####}占位符,示例:const body = ` <h2>Please verify your email</h2> <p>Hi${nameWrapper}</p> <p>Your verification code: {####}</p> `;
- 若使用链接验证:在用户池「属性验证」设置中切换为链接模式,确保模板保留
完善异常处理
添加错误日志并抛出异常,便于排查问题:catch (error) { console.error('CustomMessage handler error:', error); throw error; }确认用户池模板设置
检查用户池「验证消息」模板是否被意外启用,确保未覆盖Lambda自定义内容。
内容的提问来源于stack exchange,提问作者codebear22

