S3 URL访问被拒:Node.js+Nodemailer附件403错误排查求助
解决S3 URL访问403及Nodemailer附件问题
问题核心原因
你碰到的403错误,本质是S3桶策略未覆盖对象级权限,同时目标PDF对象可能仍处于私有状态,导致浏览器和Nodemailer都无法正常访问文件。
具体修复步骤
1. 修正S3桶策略
当前桶策略仅授权IAM root用户对桶本身的操作权限,没有覆盖桶内的具体对象(比如你要访问的testfolder/test.pdf)。需要修改Resource字段,同时包含桶和桶内所有对象:
{ "Version": "2012-10-17", "Id": "Policy1720627335118", "Statement": [ { "Sid": "Stmt1720627331285", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::946520502272:root" }, "Action": "s3:*", "Resource": [ "arn:aws:s3:::test-bucket", "arn:aws:s3:::test-bucket/*" ] } ] }
2. 调整对象ACL(如需公共访问)
如果希望直接复制URL在浏览器打开文件,需要给目标PDF对象设置公共读权限:
- 登录AWS控制台,进入对应S3桶找到
testfolder/test.pdf - 右键选择「修改权限」
- 在「对象所有者权限」或「其他用户权限」中勾选「读取」权限
3. 更安全的Nodemailer附件方案(无需开放公共访问)
如果不想暴露S3文件的公共访问权限,推荐直接通过AWS SDK从S3获取文件流,再传给Nodemailer:
const AWS = require('aws-sdk'); const s3 = new AWS.S3({ accessKeyId: '你的AWS Access Key', secretAccessKey: '你的AWS Secret Key' }); // 获取S3文件资源 const params = { Bucket: 'test-bucket', Key: 'testfolder/test.pdf' }; s3.getObject(params, (err, data) => { if (err) throw err; transporter.sendMail({ from: 'email@email.com', to: `${email}`, subject: 'test email', attachments: [{ filename: `${creation}.pdf`, content: data.Body, // 直接传入文件Buffer contentType: 'application/pdf' }], html: `<p>Greetings test</p>`, function (err, info) { if (err) { console.error(err) } else { console.log(info) } } }); });
4. 排查其他潜在限制
- 确认本地环境的AWS凭证(若用SDK方案)拥有S3读权限
- 检查桶的「访问控制列表(ACL)」是否存在额外拒绝规则
- 确认未开启存储桶策略中的IP限制等条件规则
内容的提问来源于stack exchange,提问作者Matt
相关产品推荐
相关产品推荐

