如何使用 Lambda 在 DynamoDB 中存储与 Amazon SES 电子邮件有关的 Amazon SNS 通知?

5 分钟阅读
0

对于通过 Amazon Simple Email Service(Amazon SES)发送的电子邮件,我使用 Amazon Simple Notification Service(Amazon SNS)来接收相关通知。我想创建一个 AWS Lambda 函数,将这些通知存储在 Amazon DynamoDB 表中。

解决方案

**注意:**以下步骤中的代码示例适用于使用 V3 SDK 的 Lambda Node.js 运行时,例如 Node.js 18.x 和 20.x。

**先决条件:**使用配置为接收 Amazon SES 通知的 Amazon SNS 主题来设置 Amazon SES 电子邮件或域。有关详细信息,请参阅 Receiving Amazon SES notifications using Amazon SNS

创建 DynamoDB 表

在 DynamoDB 中创建表,使其具备以下属性:

  • Table-name 中输入 SESNotifications
  • 在主分区键中输入 SESMessageId
  • 在主排序键中输入 SnsPublishTime

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

索引名称分区键排序键
SESMessageType-IndexSESMessageType(字符串)SnsPublishTime(字符串)
SESMessageComplaintType-IndexSESComplaintFeedbackType(字符串)SnsPublishTime(字符串)

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

有关信息,请参阅 Create a DynamoDB table

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

创建一个新的 AWS Identity and Access Management(IAM)角色。配置角色,允许 Lambda 函数调用 DynamoDB:PutItem API

**注意:**最佳做法是为不同的 Lambda 函数创建和使用新的 IAM 角色。请勿在多个函数中重复使用角色。

要向 Lambda 函数的 IAM 角色添加权限,请完成以下步骤:

  1. 打开 IAM 控制台
  2. 在导航窗格中,选择角色
  3. 选择创建角色
  4. 选择可信实体类型,选择 AWS 服务
  5. 选择用例选择 Lambda。然后,选择下一步: 权限
  6. 对于附加权限策略,勾选 AWSLambdaBasicExecutionRole 托管策略旁边的复选框。然后,选择下一步: 标签
  7. (可选)向角色添加 IAM 标签。有关详细信息,请参阅 Tagging IAM resources
  8. 选择下一步: 审核
  9. 角色名称* 输入 lambda_ses_execution
  10. 选择创建角色
  11. 返回 IAM 角色,然后选择角色。
  12. 权限选项卡上,选择添加内联策略
  13. 可视化编辑器选项卡上,选择**“选择服务”**。
  14. 选择 DynamoDB
  15. 操作搜索字段中,输入 PutItem。在下拉列表中,选中 PutItem 旁边的复选框。
  16. 资源选择特定
  17. 选择添加 ARN。然后,在文本框中输入 DynamoDB 表的 ARN
  18. 选择查看策略
  19. 名称中输入策略的名称。
  20. 选择创建策略

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

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

创建 Lambda 函数来处理 Amazon SES 和 Amazon SNS 通知

使用以下示例函数代码创建名为 sesnotificationscodeLambda 函数。可以将以下示例 Lambda 函数用作模板,将数据写入客户关系管理(CRM)系统或其他目标。

**重要事项:**为该函数分配 lambda_ses_execution 角色。

console.log("Loading event");

import { DynamoDBClient, PutItemCommand } from "@aws-sdk/client-dynamodb";
const client = new DynamoDBClient({});

export const handler = async (event) => {
  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 = {
      TableName: "SESNotifications",
      Item: {
        SESMessageId: { S: SESMessageId },
        SnsPublishTime: { S: SnsPublishTime },
        SESreportingMTA: { S: SESreportingMTA },
        SESDestinationAddress: { S: SESDestinationAddress },
        SESbounceSummary: { S: SESbounceSummary },
        SESMessageType: { S: SESMessageType },
      },
    };
    const command = new PutItemCommand(itemParams);
    try {
    const response = await client.send(command);
    console.log("Put Item Response Bounce: ", response);
    } catch (err) {
     console.log("Error", err);
    }  

  } else if (SESMessageType == "Delivery") {
    var SESsmtpResponse1 = SESMessage.delivery.smtpResponse;
    var SESreportingMTA1 = SESMessage.delivery.reportingMTA;
    var itemParamsdel = {
      TableName: "SESNotifications",
      Item: {
        SESMessageId: { S: SESMessageId },
        SnsPublishTime: { S: SnsPublishTime },
        SESsmtpResponse: { S: SESsmtpResponse1 },
        SESreportingMTA: { S: SESreportingMTA1 },
        SESDestinationAddress: { S: SESDestinationAddress },
        SESMessageType: { S: SESMessageType },
      },
    };
    const commanddel = new PutItemCommand(itemParamsdel);
    try {
    const responsedel = await client.send(commanddel);
    console.log("Put Item Response Delivery: ", responsedel);
    } catch (err) {
     console.log("Error", err);
    }
  } else if (SESMessageType == "Complaint") {
    var SESComplaintFeedbackType = SESMessage.complaint.complaintFeedbackType;
    var SESFeedbackId = SESMessage.complaint.feedbackId;
    var itemParamscomp = {
      TableName: "SESNotifications",
      Item: {
        SESMessageId: { S: SESMessageId },
        SnsPublishTime: { S: SnsPublishTime },
        SESComplaintFeedbackType: { S: SESComplaintFeedbackType },
        SESFeedbackId: { S: SESFeedbackId },
        SESDestinationAddress: { S: SESDestinationAddress },
        SESMessageType: { S: SESMessageType },
      },
    };
    const commandcomp = new PutItemCommand(itemParamscomp);
    try {
    const responsecomp = await client.send(commandcomp);
    console.log("Put Item Response complaint: ", responsecomp);
    } catch (err) {
     console.log("Error", err);
    }
  }
};

**注意:**将 TableName 参数 SESNotifications 替换为 DynamoDB 表的名称。

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

可以使用 Amazon SNS 控制台或 Lambda 控制台为 Lambda 函数订阅一个或多个 Amazon SNS 主题。

Amazon SNS 控制台

**注意:**如果在运行 AWS 命令行界面 (AWS CLI) 命令时遇到错误,请参阅排查 AWS CLI 错误。此外,确保您使用的是最新版本的 AWS CLI
必须手动向函数资源策略添加权限,允许 SNS 调用该函数。运行 add-permission AWS CLI 命令:

aws lambda add-permission --function-name my-function --action lambda:InvokeFunction --statement-id sns-my-topic \\  \--principal sns.amazonaws.com --source-arn arn:aws:sns:us-east-1:123456789012:my-topic

**注意:**将 my-functionsns-my-topicarn:aws:sns:us-east-1:123456789012:my-topic 的值替换为函数、主题和完整 ARN 的 ID。

要为函数订阅 SNS 主题,请完成以下步骤:

  1. 打开 Amazon SNS 控制台
  2. 在导航窗格中,选择主题
  3. 确定 Amazon SES 中用于退回通知的 SNS 主题。例如: 一个名为 ses_notifications_repo 的 SNS 主题。
  4. 选择 SNS 主题的 ARN。
  5. 选择创建订阅
  6. 协议选择 AWS Lambda
  7. 端点中输入 Lambda 函数的 ARN。
  8. 选择创建订阅
  9. (可选)对要订阅函数的每个通知主题重复前面的步骤。

Lambda 控制台

要使用 Lambda 控制台为 Lambda 函数订阅一个或多个 SNS 主题,请完成以下步骤:

  1. 打开 Lambda 控制台
  2. 在导航窗格中,选择函数
  3. 选择您的 Lambda 函数。
  4. 函数概述窗格上,选择 +添加触发器
  5. 触发器配置下拉列表中,选择 SNS
  6. SNS 主题下拉列表中,选择 SNS 主题。
  7. 选择添加
  8. (可选)对要订阅函数的每个通知主题重复前面的步骤。

测试设置

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

**注意:**发送测试消息时,使用其中一个邮箱模拟器地址可以防止对您的 SES 送达率指标产生负面影响。

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

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

**重要事项:**不能使用这些事件数据示例,因为这些示例是为在 Lambda 控制台中发送测试消息而编写的。必须将 eventType 消息密钥更改为 notificationType。如果不更改消息键,则测试将会失败。

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

要查询、排序 DynamoDB 表的内容并将其下载为 .csv 文件,请完成以下步骤:

  1. 打开 DynamoDB 控制台
  2. 选择 SESNotifications 表。
  3. 选择项目选项卡。
  4. 创建查询扫描搜索。有关详情信息,请参阅 Best practices for querying and scanning data
    **注意:**可以使用 DynamoDB 表导出功能,定期将文件下载到 Amazon Simple Storage Service(Amazon S3)存储桶。有关详细信息,请参阅 DynamoDB 数据导出到 Amazon S3:工作原理

相关信息

Lambda 函数的扇出

通过 Amazon SNS 调用 AWS Lambda 函数

使用 Amazon SNS 接收 Amazon SES 通知

AWS 官方
AWS 官方已更新 6 个月前