[MANDATORY] Lab 3.6: Building Amazon SES email events database


title: “[必修] 实验室 3.6: 构建 Amazon SES 电子邮件事件数据库” weight: 46


在前面的实验中,我们学习了如何使用 SNS、CloudWatch 和 Kinesis Data Firehose 设置事件通知。在本实验中,我们将利用之前实验中所学的知识,构建一个端到端的数据管道,将 Amazon SES 事件转换为分析。

先决条件

在开始本实验之前,我们应该已经完成以下内容:

描述

该解决方案与计划或已经使用 Amazon SES 发送电子邮件的任何人都相关。它使我们能够将电子邮件事件存储在 Amazon S3 中,并使用 Amazon Athena 执行 SQL 查询。

解决方案

本存储库中提供的解决方案利用 AWS CloudFormation 部署 Amazon Kinesis Firehose、Amazon S3 存储桶、AWS Glue 数据库和 Amazon Athena 表,分别用于流式传输、存储和查询电子邮件参与事件。

关于该解决方案中使用的 AWS 服务的一些信息:

  • Amazon Kinesis Data Firehose 是一种可靠捕获、转换和传送流数据到数据湖、数据存储和分析服务的提取、转换和加载 (ETL) 服务。
  • Amazon S3 通过 Web 服务接口提供对象存储。
  • AWS Glue 是一种无服务器数据集成服务,可以更轻松地发现、准备、移动和集成来自多个源的数据,用于分析、机器学习 (ML) 和应用程序开发。
  • Amazon Athena 是一种无服务器、交互式分析服务,提供了一种简化和灵活的方式来分析存储在原处的 PB 级数据。

该解决方案创建了一个包含所有电子邮件事件的表和一个 Amazon Athena 视图,该视图包含每个 message_id 的最新参与事件时间戳。该视图可用于检查最新的电子邮件状态,以及它是否已发送、已送达、已打开、已点击、已退回或产生了投诉。

实施

  1. 导航到我们要部署解决方案的 AWS 区域中的 AWS CloudShell。如果所需的 AWS 区域中没有 AWS CloudShell,则使用本地 AWS CLI
  2. 执行下面的命令将 AWS CloudFormation 模板复制到本地存储:
wget https://github.com/aws-samples/communication-developer-services-reference-architectures/blob/master/cloudformation/SES_Event_DB/ses-events-db.yaml
  1. Amazon S3 存储桶名称必须是唯一的,因此下面的命令将使用一个静态字符串、我们的 AWS 账户 ID 和一个随机的五个字符字符串来创建一个唯一的名称。
# 获取 AWS 账户 ID
ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)

# 生成随机 ID (小写,至少 5 个字符)
RANDOM_ID=$(LC_CTYPE=C tr -dc 'a-z0-9' < /dev/urandom | fold -w 5 | head -n 1)

# 确保 RANDOM_ID 至少有 8 个字符
while [ ${#RANDOM_ID} -lt 5 ]; do
  RANDOM_ID="${RANDOM_ID}$(LC_CTYPE=C tr -dc 'a-z0-9' < /dev/urandom | fold -w 1 | head -n 1)"
done

# 创建一个具有唯一名称的 S3 存储桶 (小写)
BUCKET_NAME="ses-db-${ACCOUNT_ID}-${RANDOM_ID}"
echo "S3 存储桶名称: ${BUCKET_NAME}"

# Amazon SES 配置集名称
CONFIGURATION_NAME="event-db-config"
echo "SES 配置集名称: ${CONFIGURATION_NAME}"
  1. 要部署 AWS CloudFormation 堆栈,请执行下面的 AWS CLI deploy 命令。此 AWS CloudFormation 模板包含两个参数:
  • EventAthenaDatabaseName: 将作为此解决方案一部分创建的 AWS Glue 数据库的名称。
  • CreateBucketName: 将存储所有电子邮件事件的 Amazon S3 存储桶。
  • NewConfigurationSet: 如果要使用现有的 SES 配置集,请键入 “NO”,否则键入 “YES” 以创建新的 SES 配置集。下面的 AWS CLI 命令填充了值 “YES”,它将创建一个新的 SES 配置集。
  • ConfigurationSetName: 这是将被创建或更新的配置集名称,具体取决于我们在 NewConfigurationSet 下设置的值。下面的 AWS CLI 命令填充了配置集名称 “event-db-config”。

AWS CloudFormation 模板部署时间应在 4 - 6 分钟之间。

aws cloudformation deploy \
--template-file "ses-events-db.yaml" \
--stack-name SES-Email-Database \
--parameter-overrides EventAthenaDatabaseName="ses_event_db" CreateBucketName="${BUCKET_NAME}" NewConfigurationSet="YES" ConfigurationSetName="${CONFIGURATION_NAME}"\
--capabilities CAPABILITY_NAMED_IAM \
--output table
  1. 下面是 Athena 表和视图

Athena 表

Athena 表示例数据

字段名称 描述
eventtype 事件类型,例如 Send、Delivery、Complaint、Bounce、Open
mail 包括时间戳和发件人信息在内的邮件详细信息
send 电子邮件发送时的详细信息
delivery 包括时间戳和处理时间的送达详细信息
open 包括 IP 地址和时间戳的打开事件详细信息
click 包括所点击链接的点击事件详细信息
bounce 包括类型、子类型和诊断信息的退回详细信息
complaint 包括反馈类型和用户代理的投诉详细信息
reject 拒绝事件详细信息
failure 失败事件详细信息
ingest_timestamp 事件被摄取的时间戳

Athena 视图

Athena 视图示例数据

字段名称 描述
message_id 电子邮件消息的唯一标识符
subject 电子邮件的主题行
destination 收件人电子邮件地址的数组
time_sent 电子邮件发送的时间戳
time_delivered 电子邮件送达的时间戳
time_clicked 电子邮件中的链接被点击的时间戳
time_opened 电子邮件被打开的时间戳
time_bounced 电子邮件被退回的时间戳
bounce_type 退回类型,例如 Permanent、Transient
bounce_subtype 更具体的退回类别
time_complained 投诉提交的时间戳
complaint_feedbacktype 投诉反馈类型,例如 abuse
  1. 要测试该解决方案,请使用下面的 AWS CLI 命令发送 4 - 5 封电子邮件。确保将 from-email-address 字段下的电子邮件地址更新为我们在 Amazon SES 中已验证的电子邮件地址。等待 2 分钟,然后导航到 Amazon Athena 控制台,在名为 ses_event 的数据库中预览表和 Athena。
aws sesv2 send-email \
--from-email-address "your-email@example.com" \
--destination '{"ToAddresses":["success@simulator.amazonses.com"]}' \
--content "{\"Simple\": {\"Subject\": {\"Data\": \"Hello world\"}, \"Body\": {\"Html\": {\"Data\": \"<h1>This is SES</h1>\"}}}}" \
--configuration-set-name "${CONFIGURATION_NAME}"

  1. 使用 SQL 查询数据。确保将 <your_db_name><to_email_address> 替换为我们的数据。

执行下面的查询以:

预览 ses_events 表。

SELECT * FROM "<your_db_name>"."ses_events"

获取发送到特定电子邮件地址的电子邮件状态。我们可以编辑此查询以按其他字段(如发送日期或发件人电子邮件地址)进行过滤。

SELECT *
FROM "<your_db_name>"."email_status"
CROSS JOIN UNNEST(destination) AS t(email)
WHERE t.email = '<to_email_address>'
ORDER BY time_sent DESC;