如何在Node.js中拼接AWS数据生成的message并传递给SendEmail函数
解决AWS IAM组和用户信息拼接及邮件发送的异步问题
你的代码核心问题在于异步操作的顺序控制——iam.listGroups和iam.getGroup都是异步回调式的API,当前代码不仅没有调用SendEmail函数,就算调用了,也会在所有组的用户信息还没完成拼接时就执行,最终得到不完整的message。
下面是重构后的完整解决方案,使用async/await(Node.js 8.10+支持,Lambda默认环境已兼容)来清晰控制异步流程,确保所有信息拼接完成后再发送邮件:
const aws = require('aws-sdk'); const ses = new aws.SES({ region: 'us-east-1' }); const iam = new aws.IAM({ apiVersion: '2010-05-08' }); // 将IAM listGroups方法包装为Promise,方便使用await const listIamGroups = () => { return new Promise((resolve, reject) => { iam.listGroups({}, (err, data) => { if (err) reject(err); else resolve(data.Groups); }); }); }; // 将IAM getGroup方法包装为Promise,按组名获取用户 const getGroupUsers = (groupName) => { return new Promise((resolve, reject) => { iam.getGroup({ GroupName: groupName }, (err, data) => { if (err) reject(err); else resolve(data.Users); }); }); }; // 邮件发送函数(补充了SES实际发送的示例逻辑) const sendEmail = async (messageContent) => { console.log('===SENDING EMAIL HERE using message variable==='); // 配置SES发送参数(请替换为你的发件人、收件人信息) const sesParams = { Destination: { ToAddresses: ['your-recipient@example.com'] }, Message: { Body: { Html: { Charset: 'UTF-8', Data: messageContent // 拼接好的HTML格式内容 } }, Subject: { Charset: 'UTF-8', Data: 'AWS IAM Groups & Users Report' } }, Source: 'your-sender@example.com' // 需要在SES中验证该邮箱 }; try { await ses.sendEmail(sesParams).promise(); console.log('Email sent successfully!'); } catch (emailErr) { console.error('Failed to send email:', emailErr); throw emailErr; // 抛出错误让上层处理 } }; exports.handler = async (event, context) => { console.log("Incoming event: ", event); let message = ""; try { // 第一步:获取所有IAM组 const allGroups = await listIamGroups(); // 第二步:遍历每个组,获取用户并拼接内容 for (const group of allGroups) { // 添加组名(用加粗标签增强邮件可读性) message += `<h3>${group.GroupName}</h3>`; // 获取当前组下的所有用户 const groupUsers = await getGroupUsers(group.GroupName); // 拼接用户信息 if (groupUsers.length === 0) { message += "<p>No users assigned to this group</p><hr/>"; } else { message += "<ul>"; for (const user of groupUsers) { // 处理PasswordLastUsed可能为undefined的情况 const lastUsed = user.PasswordLastUsed ? user.PasswordLastUsed.toLocaleString() : "Never"; message += `<li>${user.UserName} - Password Last Used: ${lastUsed}</li>`; } message += "</ul><hr/>"; } } // 第三步:所有内容拼接完成后,发送邮件 await sendEmail(message); console.log('IAM report generated and email sent successfully'); } catch (err) { console.error('Process failed:', err); // 这里可以添加错误处理逻辑,比如发送告警邮件 } };
关键改进点说明:
- 异步流程控制:用
Promise包装AWS SDK的回调式API,结合async/await让异步代码像同步代码一样顺序执行,确保先获取所有组,再逐个获取每个组的用户,最后才发送邮件。 - 避免竞态条件:原来的代码中多个异步回调同时修改
message变量,可能导致内容混乱;现在顺序执行每个组的用户查询,不会出现并发修改问题。 - 邮件内容优化:用HTML标签(
<h3>、<ul>、<hr/>)让邮件内容结构更清晰,同时处理PasswordLastUsed为空的边界情况。 - 错误处理:用
try/catch包裹整个流程,捕获从IAM查询到邮件发送的所有错误,便于调试和异常处理。
原来代码的核心问题回顾:
- 未等待所有
iam.getGroup异步调用完成就尝试使用message(甚至没调用SendEmail); - 多个异步回调并发修改同一个
message变量,可能导致内容错乱; - 回调嵌套导致代码可读性和可维护性差。
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

