构建电子邮件归档系统:挑战与解决方案 - 第1部分

杰夫·戈德斯坦

2019年2月4日

电子邮件

1 min read

构建电子邮件归档系统:挑战与解决方案 - 第1部分

关键要点

    • Email archiving 是日益重要的,特别是在监管、合规和审计环境中。

    • SparkPost 不存储邮件正文,但其 Archive feature 允许发送者接收与跟踪链接和内容相吻合的重复消息。

    • 邮件正文可以存储在 Amazon S3 中,而消息事件元数据可以存储在 MySQL 中以供查询和交叉引用。

    • SparkPost 消息事件提供丰富的活动日志(退信、投递、点击、打开、退订、投诉等)。

    • 只有通过 SMTP 发送邮件时才会生成档案副本。

    • 原始邮件、档案邮件、CC 和 BCC 邮件的消息事件共享一个 transmission_id

    • 入站邮件中继可以摄取档案消息,但不包括 transmission_id ,这造成了数据链接的挑战。

    • 在消息正文中嵌入 hidden unique identifier (UID) 可以弥补这一差距,将入站内容与出站日志联系起来。

    • 结合档案邮件和消息事件可以建立一个可搜索的、可审核的档案系统。

    • 长期项目包括在 S3 中存储档案邮件和在 MySQL 中记录事件数据的代码发布。

    • 最终应用程序将允许轻松搜索、查看和协调邮件内容与所有相关事件历史。

    • 非常适合那些需要全面了解每封发送邮件的合规性重工业。

Q&A 精华

  • 为什么构建自己的电子邮件归档系统?

    受监管行业通常需要长期存储电子邮件正文及所有相关的事件日志。SparkPost 不存储消息正文,因此建立自定义系统以确保合规性、审计和可见性。

  • 您如何获取原始发送电子邮件的精确副本?

    SparkPost的Archive feature会将每封外发电子邮件的副本发送到指定的存档地址,保留所有编码链接和跟踪行为。

  • 为什么您无法在发送前捕获电子邮件正文?

    预发送捕获不包括SparkPost的修改(打开跟踪、点击跟踪、链接编码)。使用Archive副本确保您的保存版本与收件人收到的内容完全匹配。

  • SparkPost会自动归档电子邮件吗?

    不。SparkPost 存储消息正文。必须在 SMTP 注入期间通过指定存档地址来请求存档副本。

  • 在这个归档系统中,哪些内容存储在何处?

    • Email body → Amazon S3

    • Message event logs → MySQL
      这种分离支持快速搜索、结构化查询和低成本对象存储。

  • SparkPost 会保留事件数据多长时间?

    SparkPost 存储消息事件10天。之后,数据必须通过 webhook 获取或查询并存储在其他地方。

  • 有哪些消息事件可用?

    SparkPost 目前公开 14 个事件,包括 deliveries、bounces、clicks、opens、rejections、policy issues、spam complaints、unsubscribes, 和更多。

  • 什么标识符将所有事件联系在一起?

    所有外发邮件(原件、存档、CC、BCC)共享相同的transmission_id。原件和存档邮件也共享相同的message_id

  • 为何入站处理是一个挑战?

    SparkPost 的入站电子邮件中继将入站电子邮件转换为 JSON,但此 JSON 不包括 transmission_id。没有额外的数据,入站副本无法链接到其出站日志历史。

  • 如何将入站存档电子邮件连接到出站消息事件?

    在电子邮件正文中嵌入一个隐藏的unique identifier (UID),并在元数据中传递相同的UID。这个UID成为入站和出站记录之间的共享引用。

  • 入站电子邮件中继如何帮助自动化存档?

    它接收发送到您存档域的档案邮件,将它们解析为结构化的JSON,并通过webhook发布到您的应用程序——允许自动提取和存储。

  • 这个项目的长期愿景是什么?

    一个完整的应用程序:

    • 在 S3 中存储归档邮件

    • 在 MySQL 中存储所有事件日志

    • 允许用户搜索邮件

    • 在一个统一界面中显示原始邮件及每个相关事件

大约一年前,我写了一篇关于如何检索邮件副本以进行存档和查看的博客,但我没有涉及到电子邮件或相关数据的实际存储。最近,我写了一篇关于存储所有事件数据(例如,电子邮件发送、打开、点击、退回、取消订阅等)博客,供审核之用,但选择不创建任何支持代码。

随着监管环境中电子邮件使用的增加,我决定是时候开始一个新项目,将所有这些整合在一起,并配有如何存储电子邮件正文及其相关数据的代码示例。在接下来的一年里,我将继续在这个项目上进行构建,目的是创建一个可用于存档电子邮件和所有由SparkPost生成的日志信息的存储和查看应用程序。SparkPost 没有存档电子邮件正文的系统,但它确实使构建档案平台变得相当容易。

在这个博客系列中,我将描述我经过的过程,以便将电子邮件正文存储到 S3(亚马逊简单存储服务)中,并将所有相关日志数据存储在 MySQL 中以便于交叉引用。对于需要稳健数据库备份策略的生产存档系统,考虑实施一个全面的PostgreSQL 备份和恢复流程,以确保您的存档数据得到妥善保护。最终,这是构建一个可以轻松搜索存档电子邮件的应用程序的起点,然后显示这些电子邮件和事件(日志)数据。此项目的代码可以在以下 GitHub 仓库中找到:PHPArchivePlatform on GitHub

本博客系列的第一篇文章将描述挑战并为解决方案布局架构。其余的博客将详细介绍解决方案的各个部分,并附带代码示例。

我流程的第一步是弄清楚如何获得发送给原始收件人的电子邮件副本。为了获得电子邮件正文的副本,您需要:


电子邮件正文捕获选项

方法

谁创建副本

反映跟踪更改

自动化友好

用于此解决方案

发送前捕获

应用程序

❌ 否

✅ 是

电子邮件服务器存储副本

邮件服务器

✅ 是

❌ 有限

SparkPost Archive 功能

SparkPost

✅ 是

✅ 是


  1. 在发送电子邮件之前捕获电子邮件正文

  2. 让电子邮件服务器存储副本

  3. 让电子邮件服务器创建一个副本供您存储

如果电子邮件服务器正在添加链接跟踪或打开跟踪等项目,您不能使用#1,因为它不会反映打开/点击跟踪更改。

这意味着服务器要么必须存储电子邮件,要么以某种方式提供该电子邮件的副本供您存储。由于 SparkPost 没有用于电子邮件正文的存储机制,但确实有一种方法可以创建电子邮件的副本,我们将让 SparkPost 将电子邮件的副本发给我们,以便我们存储在 S3 中。

这通过使用 SparkPost 的 Archive 功能来实现。SparkPost 的 Archive 功能使发送者能够告诉 SparkPost 将电子邮件的副本发送到一个或多个电子邮件地址,并使用与原始邮件相同的跟踪和打开链接。SparkPost 文档以下面的方式定义其 Archive 功能:

档案列表中的收件人将收到与发送到 RCPT TO 地址的消息完全相同的副本。特别是,任何为 RCPT TO 收件人编码的链接在档案邮件中都将是相同的。

与 RCPT TO 邮件的唯一区别是,一些标题会有所不同,因为归档邮件的目标地址不同,但电子邮件的正文将是完全相同的副本!

如果您想要更深入的解释,这里是创建电子邮件的副本(或归档)的SparkPost 文档的链接。

附带说明,SparkPost 实际上允许您将电子邮件发送到 cc、bcc 和存档电子邮件地址。对于此解决方案,我们专注于存档地址。

* 注意 * 存档电子邮件只能在通过 SMTP 将电子邮件注入 SparkPost 时创建!

现在我们知道如何获取原始电子邮件的副本,我们需要查看生成的日志数据及其数据中一些微妙的差异。SparkPost 跟踪其服务器上发生的一切,并以消息事件的形式向您提供该信息。这些事件在 SparkPost 上存储 10 天,并且可以通过称为消息事件的 RESTful API 从服务器拉取,或者您可以让 SparkPost 将这些事件推送给您希望的任何数量的收集应用程序。推送机制通过 Webhooks 实时进行。

目前,可能发生在邮件上的事件有 14 种。以下是当前事件的列表:

  • 反弹

  • 点击延迟

  • 投递

  • 生成失败

  • 生成拒绝

  • 初始打开

  • 注入链接取消订阅

  • 列表取消订阅

  • 打开

  • 带外

  • 政策拒绝垃圾投诉


* 按照此链接获取每个事件的描述以及每个事件共享的数据的最新参考指南。

每个事件都有许多与事件类型相匹配的字段。一些字段如 transmission_id 存在每个事件中,但其他字段可能更具事件特定性;例如,只有打开和点击事件才有地理标签信息。


在归档系统中使用的标识符

标识符

起源地

共享范围

目的

限制

transmission_id

SparkPost 外发

原件、存档、cc、bcc

关联所有消息事件

未在传入中可用

message_id

SparkPost 外发

原件 + 存档

识别单个消息

cc/bcc 不同

隐藏的 UID

由发送者注入

外发 + 传入

将归档邮件正文与事件链接

必须自定义实现


此项目一个非常重要的消息事件条目是 transmission_id。原件邮件、存档邮件和任何 ccbcc 地址的所有消息事件条目将共享相同的 transmission_id。

还有一个常见条目称为 message_id,它在原始邮件和存档邮件的每个条目中会有相同的 id。任何 cc 或 bcc 地址将在 message_id 条目中拥有自己的 id。

迄今为止,听起来很不错,而且坦白说相当简单,但现在是具有挑战性的部分。记住,为了获取存档邮件,我们让 SparkPost 将原件的副本发送到您可以访问的一些收件箱对应的另一个电子邮件地址。但为了自动化这一解决方案并存储电子邮件正文,我将使用 SparkPost 的另一个功能称为入站电子邮件中继。所以,会从发送到特定域的所有电子邮件中处理它们。通过处理它们,它将电子邮件分解并创建一个 JSON 结构,然后通过 Webhook 传递给应用程序。请参阅附录 A 以获取示例 JSON。

如果您仔细观察,您会注意到入站中继的 JSON 结构中缺少一个非常重要的字段;那就是 transmission_id。而所有外发的邮件都有相同的 transmission_id 条目,它将原件邮件、存档、cc 和 bcc 地址的数据绑定在一起;由于 SparkPost 没有办法知道通过入站进程捕获的电子邮件是与任何外发邮件连接在一起了。因此,入站进程只知道有一个电子邮件被发往特定域并解构了,但它不知道是客户的回复还是SparkPost 的存档邮件。

所以,您需要解决的问题是:如何将外发数据连接到刚刚抓取到存档电子邮件的入站进程中?我决定在电子邮件正文中隐藏一个唯一标识符。至于如何实现,这取决于您,但我只是创建了一个隐藏标签为打开状态的输入字段。

<input name="ArchiveCode" type="hidden" value="<<UID>>">

我还将该字段添加到在注入期间传递给 SparkPost 的 X-MSYS-API 标头的元数据块中。这个隐藏的 UID 将成为整个过程的粘合剂,并且是项目的一个主要组成部分,随后在接下来的博客文章中会深入讨论。

现在我们有了能够将这个项目粘合在一起的 UID,并理解它的必要性,我可以开始构建整个项目的愿景以及相应的博客文章了。

  1. 捕获和存储存档邮件以及数据库条目用于搜索/索引

  2. 捕获所有消息事件数据

  3. 创建一个应用程序来查看电子邮件及所有相应数据

以下是项目的简单图示:

build an email archiving system - diagram


首个代码投放将涵盖存档过程并将电子邮件存储到 S3,第二个代码投放将涵盖将所有的日志数据从消息事件存储到 MySQL。你可以期待在 2019 年初的第一个代码投放和博客文章。如果你有任何问题或建议,请随时传递给我们。

发送愉快。
—— 杰夫


附录 A:

JSON file example - email archiving system

大约一年前,我写了一篇关于如何检索邮件副本以进行存档和查看的博客,但我没有涉及到电子邮件或相关数据的实际存储。最近,我写了一篇关于存储所有事件数据(例如,电子邮件发送、打开、点击、退回、取消订阅等)博客,供审核之用,但选择不创建任何支持代码。

随着监管环境中电子邮件使用的增加,我决定是时候开始一个新项目,将所有这些整合在一起,并配有如何存储电子邮件正文及其相关数据的代码示例。在接下来的一年里,我将继续在这个项目上进行构建,目的是创建一个可用于存档电子邮件和所有由SparkPost生成的日志信息的存储和查看应用程序。SparkPost 没有存档电子邮件正文的系统,但它确实使构建档案平台变得相当容易。

在这个博客系列中,我将描述我经过的过程,以便将电子邮件正文存储到 S3(亚马逊简单存储服务)中,并将所有相关日志数据存储在 MySQL 中以便于交叉引用。对于需要稳健数据库备份策略的生产存档系统,考虑实施一个全面的PostgreSQL 备份和恢复流程,以确保您的存档数据得到妥善保护。最终,这是构建一个可以轻松搜索存档电子邮件的应用程序的起点,然后显示这些电子邮件和事件(日志)数据。此项目的代码可以在以下 GitHub 仓库中找到:PHPArchivePlatform on GitHub

本博客系列的第一篇文章将描述挑战并为解决方案布局架构。其余的博客将详细介绍解决方案的各个部分,并附带代码示例。

我流程的第一步是弄清楚如何获得发送给原始收件人的电子邮件副本。为了获得电子邮件正文的副本,您需要:


电子邮件正文捕获选项

方法

谁创建副本

反映跟踪更改

自动化友好

用于此解决方案

发送前捕获

应用程序

❌ 否

✅ 是

电子邮件服务器存储副本

邮件服务器

✅ 是

❌ 有限

SparkPost Archive 功能

SparkPost

✅ 是

✅ 是


  1. 在发送电子邮件之前捕获电子邮件正文

  2. 让电子邮件服务器存储副本

  3. 让电子邮件服务器创建一个副本供您存储

如果电子邮件服务器正在添加链接跟踪或打开跟踪等项目,您不能使用#1,因为它不会反映打开/点击跟踪更改。

这意味着服务器要么必须存储电子邮件,要么以某种方式提供该电子邮件的副本供您存储。由于 SparkPost 没有用于电子邮件正文的存储机制,但确实有一种方法可以创建电子邮件的副本,我们将让 SparkPost 将电子邮件的副本发给我们,以便我们存储在 S3 中。

这通过使用 SparkPost 的 Archive 功能来实现。SparkPost 的 Archive 功能使发送者能够告诉 SparkPost 将电子邮件的副本发送到一个或多个电子邮件地址,并使用与原始邮件相同的跟踪和打开链接。SparkPost 文档以下面的方式定义其 Archive 功能:

档案列表中的收件人将收到与发送到 RCPT TO 地址的消息完全相同的副本。特别是,任何为 RCPT TO 收件人编码的链接在档案邮件中都将是相同的。

与 RCPT TO 邮件的唯一区别是,一些标题会有所不同,因为归档邮件的目标地址不同,但电子邮件的正文将是完全相同的副本!

如果您想要更深入的解释,这里是创建电子邮件的副本(或归档)的SparkPost 文档的链接。

附带说明,SparkPost 实际上允许您将电子邮件发送到 cc、bcc 和存档电子邮件地址。对于此解决方案,我们专注于存档地址。

* 注意 * 存档电子邮件只能在通过 SMTP 将电子邮件注入 SparkPost 时创建!

现在我们知道如何获取原始电子邮件的副本,我们需要查看生成的日志数据及其数据中一些微妙的差异。SparkPost 跟踪其服务器上发生的一切,并以消息事件的形式向您提供该信息。这些事件在 SparkPost 上存储 10 天,并且可以通过称为消息事件的 RESTful API 从服务器拉取,或者您可以让 SparkPost 将这些事件推送给您希望的任何数量的收集应用程序。推送机制通过 Webhooks 实时进行。

目前,可能发生在邮件上的事件有 14 种。以下是当前事件的列表:

  • 反弹

  • 点击延迟

  • 投递

  • 生成失败

  • 生成拒绝

  • 初始打开

  • 注入链接取消订阅

  • 列表取消订阅

  • 打开

  • 带外

  • 政策拒绝垃圾投诉


* 按照此链接获取每个事件的描述以及每个事件共享的数据的最新参考指南。

每个事件都有许多与事件类型相匹配的字段。一些字段如 transmission_id 存在每个事件中,但其他字段可能更具事件特定性;例如,只有打开和点击事件才有地理标签信息。


在归档系统中使用的标识符

标识符

起源地

共享范围

目的

限制

transmission_id

SparkPost 外发

原件、存档、cc、bcc

关联所有消息事件

未在传入中可用

message_id

SparkPost 外发

原件 + 存档

识别单个消息

cc/bcc 不同

隐藏的 UID

由发送者注入

外发 + 传入

将归档邮件正文与事件链接

必须自定义实现


此项目一个非常重要的消息事件条目是 transmission_id。原件邮件、存档邮件和任何 ccbcc 地址的所有消息事件条目将共享相同的 transmission_id。

还有一个常见条目称为 message_id,它在原始邮件和存档邮件的每个条目中会有相同的 id。任何 cc 或 bcc 地址将在 message_id 条目中拥有自己的 id。

迄今为止,听起来很不错,而且坦白说相当简单,但现在是具有挑战性的部分。记住,为了获取存档邮件,我们让 SparkPost 将原件的副本发送到您可以访问的一些收件箱对应的另一个电子邮件地址。但为了自动化这一解决方案并存储电子邮件正文,我将使用 SparkPost 的另一个功能称为入站电子邮件中继。所以,会从发送到特定域的所有电子邮件中处理它们。通过处理它们,它将电子邮件分解并创建一个 JSON 结构,然后通过 Webhook 传递给应用程序。请参阅附录 A 以获取示例 JSON。

如果您仔细观察,您会注意到入站中继的 JSON 结构中缺少一个非常重要的字段;那就是 transmission_id。而所有外发的邮件都有相同的 transmission_id 条目,它将原件邮件、存档、cc 和 bcc 地址的数据绑定在一起;由于 SparkPost 没有办法知道通过入站进程捕获的电子邮件是与任何外发邮件连接在一起了。因此,入站进程只知道有一个电子邮件被发往特定域并解构了,但它不知道是客户的回复还是SparkPost 的存档邮件。

所以,您需要解决的问题是:如何将外发数据连接到刚刚抓取到存档电子邮件的入站进程中?我决定在电子邮件正文中隐藏一个唯一标识符。至于如何实现,这取决于您,但我只是创建了一个隐藏标签为打开状态的输入字段。

<input name="ArchiveCode" type="hidden" value="<<UID>>">

我还将该字段添加到在注入期间传递给 SparkPost 的 X-MSYS-API 标头的元数据块中。这个隐藏的 UID 将成为整个过程的粘合剂,并且是项目的一个主要组成部分,随后在接下来的博客文章中会深入讨论。

现在我们有了能够将这个项目粘合在一起的 UID,并理解它的必要性,我可以开始构建整个项目的愿景以及相应的博客文章了。

  1. 捕获和存储存档邮件以及数据库条目用于搜索/索引

  2. 捕获所有消息事件数据

  3. 创建一个应用程序来查看电子邮件及所有相应数据

以下是项目的简单图示:

build an email archiving system - diagram


首个代码投放将涵盖存档过程并将电子邮件存储到 S3,第二个代码投放将涵盖将所有的日志数据从消息事件存储到 MySQL。你可以期待在 2019 年初的第一个代码投放和博客文章。如果你有任何问题或建议,请随时传递给我们。

发送愉快。
—— 杰夫


附录 A:

JSON file example - email archiving system

大约一年前,我写了一篇关于如何检索邮件副本以进行存档和查看的博客,但我没有涉及到电子邮件或相关数据的实际存储。最近,我写了一篇关于存储所有事件数据(例如,电子邮件发送、打开、点击、退回、取消订阅等)博客,供审核之用,但选择不创建任何支持代码。

随着监管环境中电子邮件使用的增加,我决定是时候开始一个新项目,将所有这些整合在一起,并配有如何存储电子邮件正文及其相关数据的代码示例。在接下来的一年里,我将继续在这个项目上进行构建,目的是创建一个可用于存档电子邮件和所有由SparkPost生成的日志信息的存储和查看应用程序。SparkPost 没有存档电子邮件正文的系统,但它确实使构建档案平台变得相当容易。

在这个博客系列中,我将描述我经过的过程,以便将电子邮件正文存储到 S3(亚马逊简单存储服务)中,并将所有相关日志数据存储在 MySQL 中以便于交叉引用。对于需要稳健数据库备份策略的生产存档系统,考虑实施一个全面的PostgreSQL 备份和恢复流程,以确保您的存档数据得到妥善保护。最终,这是构建一个可以轻松搜索存档电子邮件的应用程序的起点,然后显示这些电子邮件和事件(日志)数据。此项目的代码可以在以下 GitHub 仓库中找到:PHPArchivePlatform on GitHub

本博客系列的第一篇文章将描述挑战并为解决方案布局架构。其余的博客将详细介绍解决方案的各个部分,并附带代码示例。

我流程的第一步是弄清楚如何获得发送给原始收件人的电子邮件副本。为了获得电子邮件正文的副本,您需要:


电子邮件正文捕获选项

方法

谁创建副本

反映跟踪更改

自动化友好

用于此解决方案

发送前捕获

应用程序

❌ 否

✅ 是

电子邮件服务器存储副本

邮件服务器

✅ 是

❌ 有限

SparkPost Archive 功能

SparkPost

✅ 是

✅ 是


  1. 在发送电子邮件之前捕获电子邮件正文

  2. 让电子邮件服务器存储副本

  3. 让电子邮件服务器创建一个副本供您存储

如果电子邮件服务器正在添加链接跟踪或打开跟踪等项目,您不能使用#1,因为它不会反映打开/点击跟踪更改。

这意味着服务器要么必须存储电子邮件,要么以某种方式提供该电子邮件的副本供您存储。由于 SparkPost 没有用于电子邮件正文的存储机制,但确实有一种方法可以创建电子邮件的副本,我们将让 SparkPost 将电子邮件的副本发给我们,以便我们存储在 S3 中。

这通过使用 SparkPost 的 Archive 功能来实现。SparkPost 的 Archive 功能使发送者能够告诉 SparkPost 将电子邮件的副本发送到一个或多个电子邮件地址,并使用与原始邮件相同的跟踪和打开链接。SparkPost 文档以下面的方式定义其 Archive 功能:

档案列表中的收件人将收到与发送到 RCPT TO 地址的消息完全相同的副本。特别是,任何为 RCPT TO 收件人编码的链接在档案邮件中都将是相同的。

与 RCPT TO 邮件的唯一区别是,一些标题会有所不同,因为归档邮件的目标地址不同,但电子邮件的正文将是完全相同的副本!

如果您想要更深入的解释,这里是创建电子邮件的副本(或归档)的SparkPost 文档的链接。

附带说明,SparkPost 实际上允许您将电子邮件发送到 cc、bcc 和存档电子邮件地址。对于此解决方案,我们专注于存档地址。

* 注意 * 存档电子邮件只能在通过 SMTP 将电子邮件注入 SparkPost 时创建!

现在我们知道如何获取原始电子邮件的副本,我们需要查看生成的日志数据及其数据中一些微妙的差异。SparkPost 跟踪其服务器上发生的一切,并以消息事件的形式向您提供该信息。这些事件在 SparkPost 上存储 10 天,并且可以通过称为消息事件的 RESTful API 从服务器拉取,或者您可以让 SparkPost 将这些事件推送给您希望的任何数量的收集应用程序。推送机制通过 Webhooks 实时进行。

目前,可能发生在邮件上的事件有 14 种。以下是当前事件的列表:

  • 反弹

  • 点击延迟

  • 投递

  • 生成失败

  • 生成拒绝

  • 初始打开

  • 注入链接取消订阅

  • 列表取消订阅

  • 打开

  • 带外

  • 政策拒绝垃圾投诉


* 按照此链接获取每个事件的描述以及每个事件共享的数据的最新参考指南。

每个事件都有许多与事件类型相匹配的字段。一些字段如 transmission_id 存在每个事件中,但其他字段可能更具事件特定性;例如,只有打开和点击事件才有地理标签信息。


在归档系统中使用的标识符

标识符

起源地

共享范围

目的

限制

transmission_id

SparkPost 外发

原件、存档、cc、bcc

关联所有消息事件

未在传入中可用

message_id

SparkPost 外发

原件 + 存档

识别单个消息

cc/bcc 不同

隐藏的 UID

由发送者注入

外发 + 传入

将归档邮件正文与事件链接

必须自定义实现


此项目一个非常重要的消息事件条目是 transmission_id。原件邮件、存档邮件和任何 ccbcc 地址的所有消息事件条目将共享相同的 transmission_id。

还有一个常见条目称为 message_id,它在原始邮件和存档邮件的每个条目中会有相同的 id。任何 cc 或 bcc 地址将在 message_id 条目中拥有自己的 id。

迄今为止,听起来很不错,而且坦白说相当简单,但现在是具有挑战性的部分。记住,为了获取存档邮件,我们让 SparkPost 将原件的副本发送到您可以访问的一些收件箱对应的另一个电子邮件地址。但为了自动化这一解决方案并存储电子邮件正文,我将使用 SparkPost 的另一个功能称为入站电子邮件中继。所以,会从发送到特定域的所有电子邮件中处理它们。通过处理它们,它将电子邮件分解并创建一个 JSON 结构,然后通过 Webhook 传递给应用程序。请参阅附录 A 以获取示例 JSON。

如果您仔细观察,您会注意到入站中继的 JSON 结构中缺少一个非常重要的字段;那就是 transmission_id。而所有外发的邮件都有相同的 transmission_id 条目,它将原件邮件、存档、cc 和 bcc 地址的数据绑定在一起;由于 SparkPost 没有办法知道通过入站进程捕获的电子邮件是与任何外发邮件连接在一起了。因此,入站进程只知道有一个电子邮件被发往特定域并解构了,但它不知道是客户的回复还是SparkPost 的存档邮件。

所以,您需要解决的问题是:如何将外发数据连接到刚刚抓取到存档电子邮件的入站进程中?我决定在电子邮件正文中隐藏一个唯一标识符。至于如何实现,这取决于您,但我只是创建了一个隐藏标签为打开状态的输入字段。

<input name="ArchiveCode" type="hidden" value="<<UID>>">

我还将该字段添加到在注入期间传递给 SparkPost 的 X-MSYS-API 标头的元数据块中。这个隐藏的 UID 将成为整个过程的粘合剂,并且是项目的一个主要组成部分,随后在接下来的博客文章中会深入讨论。

现在我们有了能够将这个项目粘合在一起的 UID,并理解它的必要性,我可以开始构建整个项目的愿景以及相应的博客文章了。

  1. 捕获和存储存档邮件以及数据库条目用于搜索/索引

  2. 捕获所有消息事件数据

  3. 创建一个应用程序来查看电子邮件及所有相应数据

以下是项目的简单图示:

build an email archiving system - diagram


首个代码投放将涵盖存档过程并将电子邮件存储到 S3,第二个代码投放将涵盖将所有的日志数据从消息事件存储到 MySQL。你可以期待在 2019 年初的第一个代码投放和博客文章。如果你有任何问题或建议,请随时传递给我们。

发送愉快。
—— 杰夫


附录 A:

JSON file example - email archiving system

其他新闻

阅读更多来自此类别的内容

A person is standing at a desk while typing on a laptop.

完整的AI原生平台,可与您的业务一起扩展。

© 2025 Bird

A person is standing at a desk while typing on a laptop.

完整的AI原生平台,可与您的业务一起扩展。

© 2025 Bird