能否在AWS Lightsail实例上通过AWS SES发邮件?权限问题求解
在AWS Lightsail实例中使用Node.js AWS SDK调用SES发信失败的问题
问题背景
我在AWS Lightsail实例上运行Node.js AWS SDK代码调用SES发送邮件时失败,但相同代码在本地开发环境正常运行。Lightsail上的WordPress通过WP Mail SMTP用SES SMTP凭证(TLS 587端口)能正常发信,说明实例本身可以和SES通信。
之前误以为是25端口限制,提交解除请求被拒,AWS建议用SES,但后续询问Lightsail能否用SES发信得到“无法批准请求”的回复,怀疑是自动回复。
报错信息
AccessDenied: User
arn:aws:sts::(some number):assumed-role/AmazonLightsailInstanceRole/i-(some alphanumeric number)is not authorized to performses:SendEmailon resource `arn:aws:ses:us-east-1:(some number):identity/(recipient email address)'
代码片段
import { readFile } from 'fs/promises'; import * as path from 'path'; import { SESClient, SendEmailCommand } from "@aws-sdk/client-ses"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const awsConfigFileFullName = "aws_config.json"; let awsConfigFileFullPath = path.join(__dirname, awsConfigFileFullName); const awsConfig = await readFile(awsConfigFileFullPath).then(json => JSON.parse(json)).catch(() => null); const aws_ses_client = new SESClient({ region: awsConfig.region, accessKeyId: awsConfig.accessKeyId, secretAccessKey: awsConfig.secretAccessKey }); const createSendEmailCommand = (toAddress, fromAddress, htmlContent, textContent, emailSubject) => { return new SendEmailCommand({ Destination: { ToAddresses: [toAddress], }, Message: { Body: { Html: { Charset: "UTF-8", Data: htmlContent, }, Text: { Charset: "UTF-8", Data: textContent, }, }, Subject: { Charset: "UTF-8", Data: emailSubject, }, }, Source: `${emailSenderName}<${fromAddress}>`, }); }; const sendEmailCommand = createSendEmailCommand( recipientEmailAddress, senderEmailAddress, htmlEmailContent, textEmailContent, emailSubject ); try { await aws_ses_client.send(sendEmailCommand); } catch (e) { console.error("Failed to send email.", e); }
疑问
- 能否为
AmazonLightsailInstanceRole角色授予SES发信权限?如何操作? - 如何在Lightsail实例上用Node.js SDK实现SES发信?
解决方案
一、为AmazonLightsailInstanceRole添加SES权限
Lightsail实例关联的AmazonLightsailInstanceRole默认不在IAM控制台直接显示,可通过以下两种方式修改权限:
Lightsail控制台操作
- 登录Lightsail控制台,进入目标实例详情页
- 切换到权限标签页,点击附加策略
- 选择
AmazonSESFullAccess(或自定义更严格的策略)完成附加
AWS CLI自定义最小权限策略
- 创建自定义策略文件
ses-send-policy.json:{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "ses:SendEmail", "Resource": "arn:aws:ses:你的区域:你的AWS账号ID:identity/你的发件邮箱地址" } ] } - 执行CLI命令附加策略:
aws iam put-role-policy --role-name AmazonLightsailInstanceRole --policy-name SES-Send-Email-Policy --policy-document file://ses-send-policy.json - 替换命令中的区域、账号ID和发件邮箱地址
- 创建自定义策略文件
二、Node.js SDK发信的正确实现
修复代码问题
- 补充导入
SendEmailCommand(原代码遗漏) Source字段直接用模板字符串拼接,无需转义<>- 优先使用实例角色身份验证(无需硬编码密钥,SDK自动从实例元数据获取凭证):
const aws_ses_client = new SESClient({ region: awsConfig.region });
- 补充导入
备选方案:用SMTP协议发送
借助nodemailer库通过SES SMTP发送(和WordPress插件逻辑一致):import nodemailer from 'nodemailer'; const transporter = nodemailer.createTransport({ host: 'email-smtp.你的区域.amazonaws.com', port: 587, secure: false, auth: { user: '你的SES SMTP用户名', pass: '你的SES SMTP密码' } }); const mailOptions = { from: `${emailSenderName}<${senderEmailAddress}>`, to: recipientEmailAddress, subject: emailSubject, text: textEmailContent, html: htmlEmailContent }; try { await transporter.sendMail(mailOptions); console.log('Email sent successfully'); } catch (error) { console.error('Error sending email:', error); }
验证步骤
- 确认SES发件邮箱已验证(或账户已移出沙箱)
- 在Lightsail实例中执行
aws ses send-email --from 发件邮箱 --to 收件邮箱 --subject "Test" --text "Test content",验证权限配置是否生效 - 运行修改后的Node.js代码,检查发信状态
内容的提问来源于stack exchange,提问作者Coder1979
相关产品推荐
相关产品推荐

