如何使用 Lambda 将 Amazon SES 电子邮件的 Amazon SNS 通知存储于 DynamoDB 中?

上次更新日期:2021 年 11 月 11 日

我使用 Amazon Simple Notification Service (Amazon SNS) 接收有关通过 Amazon Simple Email Service (Amazon SES) 发送的电子邮件的通知。如何设置 AWS Lambda 函数,以便将这些通知存储于 Amazon DynamoDB 表中?

解决方法

注意:以下示例 Lambda 函数可用作向客户关系管理 (CRM) 系统或其他目标写入数据的模板。

(先决条件)设置 Amazon SES 电子邮件或域,使其具有配置为接收来自 Amazon SES 的通知的 Amazon SNS 主题。

有关更多信息,请参阅使用 Amazon SNS 接收 Amazon SES 通知

创建 DynamoDB 表

1.    在 DynamoDB 中创建一个表,使其具有以下属性:
对于 Table-name,输入 SESNotifications
对于主分区键,输入 SESMessageId。
对于主排序键,输入 SnsPublishTime

2.    要允许 Lambda 查询表和创建 Amazon SES 报告,请设置以下二级索引

索引名称 分区键 排序键
SESMessageType-Index SESMessageType (String) SnsPublishTime (String)
SESMessageComplaintType-Index SESComplaintFeedbackType (String) SnsPublishTime (String)

注意:您可以根据需要添加更多二级索引。

有关在 DynamoDB 中创建表的信息,请参阅 Amazon DynamoDB 入门

向 Lambda 函数的 IAM 角色添加权限,使其能够调用 DynamoDB 表

创建新的 AWS Identity and Access Management (IAM) 角色。通过执行以下操作配置角色,以允许 Lambda 函数调用 DynamoDB:PutItem API

注意:最佳实践是为不同的 Lambda 函数创建和使用新的 IAM 角色。避免在多个函数中重用角色。

1.    在 IAM 控制台的左侧导航窗格中,选择 Roles(角色)。

2.    选择 Create Role(创建角色)。

3.    对于 Select type of trusted entity (选择受信任实体的类型),选择 AWS 服务

4.    对于 Choose a use case(选择使用案例),请选择 Lambda。选择 Next: Permissions(下一步:权限)。

5.    对于 Attach permissions policies(附加权限策略),请选择 AWSLambdaBasicExecutionRole 托管策略旁边的复选框。然后,选择 Next: Tags(下一步:标签)。

6.    (可选)为您的使用案例向角色添加 IAM 标签。有关更多信息,请参阅标记 IAM 资源

7.    选择下一步: 检查

8.    对于 Role name*(角色名称*),输入 lambda_ses_execution。

9.    选择 Create Role(创建角色)。

10.    返回 IAM Roles(IAM 角色)并选择您创建的角色。

11.    从Permissions(权限)选项卡中,选择 Add inline policy(添加内联策略)。

12.    在 Visual editor(可视化编辑器)选项卡中,选择 Choose a service(选择服务)。

13.    选择 DynamoDB

14.    在 Actions(操作)搜索字段中,输入 PutItem。在出现的下拉列表中,选中 PutItem 旁边的复选框。

15.    对于 Resources(资源),选择 Specific(特定)。

16.    选择 Add ARN(添加 ARN)。然后,在出现的文本框中,输入 DynamoDB 表的 Amazon Resource Name (ARN)

17.    选择 Review policy(查看策略)。

18.    在 Name(名称)中,为策略输入名称。

19.    选择 Create policy(创建策略)。

授予对 DynamoDB 表的访问权限的内联 IAM 策略示例

------------------------IAM Policy Begins---------------------------
{
    "Version": "2012-10-17",
    "Statement": [
         {
            "Sid": "Stmt1428510662000",
            "Effect": "Allow",
            "Action": [
                "DynamoDB:PutItem"
            ],
            "Resource": [
                "arn:aws:DynamoDB:us-east-1:12345678912:table/SESNotifications"
            ]
        }
    ]
}
------------------------IAM Policy Ends-----------------------------

创建一个 Lambda 函数以处理 Amazon SES 和 Amazon SNS 通知

使用以下示例函数代码创建 Lambda 函数,然后将其命名为 sesnotificationscode

重要提示:请确保为函数分配创建的 lambda_ses_execution 角色。

示例 Lambda 函数代码,用于检查 Amazon SNS 通知并将关联的 Amazon SES 通知置于 DynamoDB 表中

重要提示:TableName 参数 SESNotifications 替换为您的 DynamoDB 表名称。

--------------------------Lambda Code Begins------------------------
console.log("Loading event");

var aws = require("aws-sdk");
var ddb = new aws.DynamoDB({ params: { TableName: "SESNotifications" } });

exports.handler = function (event, context, callback) {
  console.log("Received event:", JSON.stringify(event, null, 2));

  var SnsPublishTime = event.Records[0].Sns.Timestamp;
  var SnsTopicArn = event.Records[0].Sns.TopicArn;
  var SESMessage = event.Records[0].Sns.Message;

  SESMessage = JSON.parse(SESMessage);

  var SESMessageType = SESMessage.notificationType;
  var SESMessageId = SESMessage.mail.messageId;
  var SESDestinationAddress = SESMessage.mail.destination.toString();
  var LambdaReceiveTime = new Date().toString();

  if (SESMessageType == "Bounce") {
    var SESreportingMTA = SESMessage.bounce.reportingMTA;
    var SESbounceSummary = JSON.stringify(SESMessage.bounce.bouncedRecipients);
    var itemParams = {
      Item: {
        SESMessageId: { S: SESMessageId },
        SnsPublishTime: { S: SnsPublishTime },
        SESreportingMTA: { S: SESreportingMTA },
        SESDestinationAddress: { S: SESDestinationAddress },
        SESbounceSummary: { S: SESbounceSummary },
        SESMessageType: { S: SESMessageType },
      },
    };
    ddb.putItem(itemParams, function (err, data) {
      if (err) {
        callback(err)
      } else {
        console.log(data);
        callback(null,'')
      }
    });
  } else if (SESMessageType == "Delivery") {
    var SESsmtpResponse1 = SESMessage.delivery.smtpResponse;
    var SESreportingMTA1 = SESMessage.delivery.reportingMTA;
    var itemParamsdel = {
      Item: {
        SESMessageId: { S: SESMessageId },
        SnsPublishTime: { S: SnsPublishTime },
        SESsmtpResponse: { S: SESsmtpResponse1 },
        SESreportingMTA: { S: SESreportingMTA1 },
        SESDestinationAddress: { S: SESDestinationAddress },
        SESMessageType: { S: SESMessageType },
      },
    };
    ddb.putItem(itemParamsdel, function (err, data) {
      if (err) {
        callback(err)
      } else {
        console.log(data);
        callback(null,'')
      }
    });
  } else if (SESMessageType == "Complaint") {
    var SESComplaintFeedbackType = SESMessage.complaint.complaintFeedbackType;
    var SESFeedbackId = SESMessage.complaint.feedbackId;
    var itemParamscomp = {
      Item: {
        SESMessageId: { S: SESMessageId },
        SnsPublishTime: { S: SnsPublishTime },
        SESComplaintFeedbackType: { S: SESComplaintFeedbackType },
        SESFeedbackId: { S: SESFeedbackId },
        SESDestinationAddress: { S: SESDestinationAddress },
        SESMessageType: { S: SESMessageType },
      },
    };
    ddb.putItem(itemParamscomp, function (err, data) {
      if (err) {
        callback(err)
      } else {
        console.log(data);
        callback(null,'')
      }
    });
  }
};
------------------------Lambda Code Ends----------------------------

为一个或多个 Amazon SNS 主题订阅 Lambda 函数

要使用 Amazon SNS 控制台为 Amazon SNS 主题订阅函数

1.    在 Amazon SNS 控制台的左侧导航窗格中,选择 Topics(主题)。

2.    确定 Amazon SES 中用于退回通知的 SNS 主题。例如,名为 ses_notifications_repo 的 SNS 主题。

3.    选择 SNS 主题的 ARN。此时将打开 Topic Details(主题详细信息)页面。

4.    选择 Create Subscription(创建订阅)。

5.    在 Protocol(协议)中,选择 AWS Lambda

6.    对于 Endpoint(端点),请输入 Lambda 函数的 ARN。

7.    选择 Create Subscription(创建订阅)。

8.    (可选)对每个想要订阅函数的其他通知主题,请重复执行步骤 1-7。

要使用 Lambda 控制台为 Amazon SNS 主题订阅函数

1.    打开 Lambda 控制台中的函数页面

2.    选择您之前创建的 Lambda 函数。

3.    在 Function overview(函数概览)窗格中,选择 +Add trigger(+添加触发器)按钮。

4.    在 Trigger configuration(触发器配置)下拉列表中,选择 SNS。此时将显示配置面板。

5.    在 SNS topic(SNS 主题)下拉列表中,选择要订阅函数的 SNS 主题。

6.    选择添加

7.    (可选)对每个想要订阅函数的其他通知主题,请重复执行步骤 1-6。

通过发送 Amazon SES 邮件来调用 Lambda 函数以测试设置

要发送测试 Amazon SES 消息,请使用可用邮箱模拟器地址之一

注意:发送测试消息时使用邮箱模拟器地址之一可以避免对 SES 送达率指标产生负面影响。

发送测试消息时,Amazon SES 会向 SNS 主题发布通知。然后,Amazon SNS 会将此通知作为 SNS 事件对象中的 JSON 转义 SES 事件通知对象,传送给 Lambda。

要使用 Lambda 控制台创建用于本地测试的示例事件,请参阅 Amazon SES 发布到 Amazon SNS 的事件数据示例

重要提示:您无法使用 Amazon SES 向 Amazon SNS 发布的事件数据示例,因为它们是专为在 Lambda 控制台中发送测试消息而编写的。要在测试台中使用示例进行测试,您必须将 eventType 消息密钥更改为 notificationType。如果不更改消息密钥,则测试将会失败。

从 DynamoDB 下载报告来查看 Amazon SES 通知

要对 DynamoDB 表的内容进行查询、排序以及下载为 CSV 文件,请执行以下操作:

1.    在 DynamoDB 控制台中,选择 SESNotifications 表。

2.    选择 Items(项目)选项卡。

3.    创建 Query(查询)或 Scan(扫描)搜索。有关更多信息,请参阅查询和扫描数据的最佳实践

注意:您可以使用 DynamoDB 表导出来安排定期将文件下载到 Amazon Simple Storage Service (Amazon S3) 存储桶。有关更多信息,请参阅将 DynamoDB 表数据导出到 Amazon S3