AWS SES推送至SNS触发Lambda时邮件内容加密无法解密
问题原因
你遇到的根本不是KMS加密场景,属于对SES发布到SNS的邮件内容格式认知偏差:
- SES接收邮件规则配置为向SNS发布完整邮件内容时,SNS消息负载里的
content字段是标准MIME原始邮件的Base64编码结果,不是KMS加密后的密文。你直接把Base64字符串传给KMS解密接口,因为不符合KMS密文的结构规范,自然会解密失败。 - 正常情况下SNS投递到Lambda的消息会自动完成静态加密的解密,只有你给SNS主题配置了客户管理型KMS密钥、且Lambda执行角色没有对应密钥的解密权限时,才会出现整个SNS消息为密文的情况,不会出现其他字段正常、仅
content字段加密的现象。
解决步骤
- 移除代码里手动调用KMS解密
content字段的逻辑,处理该字段不需要任何KMS权限。 - 对
content字段直接做Base64解码,得到原始MIME格式的邮件二进制数据。 - 用标准邮件解析库解码MIME结构,提取正文、附件、头信息即可。注意部分邮件的正文本身还会做quoted-printable或Base64的传输编码,成熟的邮件解析库会自动处理这层编码,不需要手动实现。
可直接运行的参考代码
import json import base64 import email from email.policy import default def lambda_handler(event, context): for record in event["Records"]: # 解析SNS消息体 sns_msg = json.loads(record["Sns"]["Message"]) # 直接Base64解码content字段,无需KMS操作 raw_mail_bytes = base64.b64decode(sns_msg["content"]) # 解析MIME格式邮件 mail = email.message_from_bytes(raw_mail_bytes, policy=default) # 提取基础邮件信息 mail_info = { "from": mail["From"], "to": mail["To"], "subject": mail["Subject"], "text_body": "" } # 提取纯文本正文 if mail.is_multipart(): for part in mail.walk(): c_type = part.get_content_type() c_disp = str(part.get("Content-Disposition", "")) if c_type == "text/plain" and "attachment" not in c_disp: mail_info["text_body"] = part.get_content() break else: mail_info["text_body"] = mail.get_content() # 写入自定义后续处理逻辑 print(mail_info) return mail_info
额外排查点
如果按照上述步骤解码后仍有异常,检查以下配置:
- 确认SES接收规则的SNS动作中,消息内容类型选择的是「完整邮件」,选「仅邮件头」不会返回正文内容。
- 如果你同时配置了S3投递动作,确认SNS动作开启了「直接在SNS消息中包含完整邮件内容」选项,关闭该选项时SNS只会返回S3对象路径,不会携带
content字段。 - 若SNS主题开启了KMS静态加密,给Lambda执行角色添加对应KMS密钥的
kms:Decrypt权限即可,该解密逻辑由SNS触发Lambda的流程自动完成,不需要在业务代码里手动调用KMS。
内容的提问来源于stack exchange,提问作者Sitruc
相关产品推荐
相关产品推荐

