Product

解决方案

资源

Company

Product

解决方案

资源

Company

S/MIME 第 4 部分:通过 SparkPost 入站中继 Webhook 轻松收集收件人公钥

2019年2月1日

电子邮件

1 min read

S/MIME 第 4 部分:通过 SparkPost 入站中继 Webhook 轻松收集收件人公钥

2019年2月1日

电子邮件

1 min read

S/MIME 第 4 部分:通过 SparkPost 入站中继 Webhook 轻松收集收件人公钥

在这个系列中,我们已经看到,包含 S/MIME 签名是相当直接的。发送 S/MIME 加密邮件则更复杂,因为您需要获取收件人的公钥。当您使用像 Thunderbird 这样的电子邮件客户端时,这是一回事,但应用程序生成的电子邮件流又如何运作呢?

part 1中,我们快速浏览了S/MIME,查看了在各种邮件客户端中签署和加密我们的消息流。Part 2带我们通过一个简单的命令行工具签署和加密电子邮件,然后通过SparkPost发送它们。Part 3展示了如何将安全邮件流注入到诸如Port25 PowerMTAMomentum之类的本地平台中。

在这个系列中,我们看到包含S/MIME签名是相当简单的。发送S/MIME加密邮件更复杂,因为你需要获得收件人的公钥。当你使用像Thunderbird这样的邮件客户端时,那是一回事——但应用生成的电子邮件流如何工作呢?应用生成的电子邮件,如用于约会平台的那些,需要睿智的策略来最大化参与度。看看约会应用如何创建引人入胜的触发邮件体验

但等等——进入Mordor获取那些密钥还有另一种方法。你的服务可以邀请你的客户(当然是通过邮件)给你发回一封未签名邮件到一个已知的客户服务地址。使用SparkPost Inbound Relay webhooks的神奇功能,我们将提取并存储供你使用的公钥。

我们可以将这总结为一个简单的用例:

  • 作为消息的接收者,我提供你的服务我的个人电子邮件签名,以便将来可以以S/MIME加密形式向我发送邮件。

从这里,我们来推导一些更详细的需求:

  • 我们需要一个始终在线的可靠入站电子邮件服务来接收这些签名电子邮件。

  • 邮件格式不应有特殊要求,除了它应该包含S/MIME签名。

  • 因为任何人都可以尝试向该服务发送邮件,它应该被设计成具有防御性的,例如,拒绝恶意行为者的“伪造”信息。需要有几个层次的检查。

  • 如果一切检查无误,服务将使用众所周知的纯文本隐私增强邮件(PEM)格式将证书存储在一个文件中。

还有一些非功能性需求:

  • 仅从对内部发生的响应来看,机器对机器的webhook服务可能很难看清。服务应提供详尽的人类可读的应用程序级日志。特别是,证书解析和检查应该被记录下来。

  • 我们为应用内部添加了测试案例,使用很好的Pytest框架,并在使用Travis CI与GitHub集成时自动运行那些测试。

好的——让我们开始吧!

1. 解决方案概览

这是整体解决方案的样子。

Diagram depicting a secure email flow illustrating how emails are verified using certificates for secure transmission.

2. 安装、配置和启动 web app

我们将从这部分开始,因此在处理入站中继webhooks之前,我们要对其进行全面测试。

Web应用程序包含在与第1-3部分相同的GitHub项目中,因此如果您已经遵循了这些部分,那么您已经拥有它。以下是新的内容:

  • 程序 readSMIMEsig.py – 读取电子邮件并解析出中间和用户证书。

  • 程序 webapp.py – 简单的兼容Flask的web应用程序,用于配合SparkPost入站中继webhooks。

  • webapp.ini – 上述内容的配置文件。配置文件可以方便地将相同的值传递给命令行和web应用程序。

您需要确保您的主机的TCP端口号对外开放,以接收来自外部世界的入站请求,以便SparkPost可以将消息POST到您的应用程序。如果您托管在AWS EC2上,例如,您需要配置实例的安全组

配置和启动web应用程序的说明在我们的安装指南中提供 – 这很简单。要检查您的应用程序是否正在运行并可从外部访问,您可以使用curl从另一个主机发送(空白)请求,例如:

curl -X POST https://app.trymsys.net:8855/

您应该看到类似这样的响应:

{"message":"Unknown Content-Type in request headers"}

这是一件好事 – 您的应用程序正在运行!

在您主机的webapp.log中,您会看到类似这样的输出:

2019-01-15 00:11:07,575,root,INFO,Request from 38.96.5.10,scheme=https,path=/
2019-01-15 00:11:07,575,root,INFO,| len(headers)=3,len(body)=None
2019-01-15 00:11:07,575,root,INFO,| Unknown Content-Type: None

为了让您立即在应用程序中使用真实数据,您可以从项目存储库中导入这个特定的Postman请求。这模拟了您的SparkPost账户的行为,即发送包含特定有效证书(属于我的一个测试账户)的https POST到您的应用程序。

您只需更改请求中的目标地址(在上面的灰色框中)以匹配您的安装。如果您更改了webapp.ini中的token值,请调整Postman中的header值以匹配。

如果您的应用程序正常工作,您将在Postman中看到“200 OK”的响应。您的主机webapp.log文件将包含如下输出:

2019-01-15 00:11:48,554,root,INFO,Request from 38.96.5.10,scheme=https,path=/
2019-01-15 00:11:48,554,root,INFO,| len(headers)=10,len(body)=14778
2019-01-15 00:11:48,555,root,INFO,| msg_from=bob.lumreeker@gmail.com,rcpt_to=secureme@inbound.thetucks.com,len(email_rfc822)=9223
2019-01-15 00:11:48,599,root,INFO,| from=bob.lumreeker@gmail.com,DKIM passed
2019-01-15 00:11:48,600,root,INFO,| content-type=multipart/signed; protocol="application/pkcs7-signature"; micalg=sha-256; boundary="------------ms010908020707040304020406",content-description=None
2019-01-15 00:11:48,600,root,INFO,| content-type=text/plain; charset=utf-8; format=flowed,content-description=None
2019-01-15 00:11:48,600,root,INFO,| content-type=application/pkcs7-signature; name="smime.p7s",content-description=S/MIME Cryptographic Signature
2019-01-15 00:11:48,600,root,INFO,| filename=smime.p7s,bytes=3998
2019-01-15 00:11:48,601,root,INFO,| Certificate: subject email_address=['bob.lumreeker@gmail.com'],not_valid_before=2018-10-03 00:00:00,not_valid_after=2019-10-03 23:59:59,hash_algorithm=sha256,key_size=2048 bytes, issuer={'countryName': 'GB', 'stateOrProvinceName': 'Greater Manchester', 'localityName': 'Salford', 'organizationName': 'COMODO CA Limited', 'commonName': 'COMODO RSA Client Authentication and Secure Email CA'}
2019-01-15 00:11:48,602,root,INFO,| Certificate: subject email_address=[],not_valid_before=2013-01-10 00:00:00,not_valid_after=2028-01-09 23:59:59,hash_algorithm=sha384,key_size=2048 bytes, issuer={'countryName': 'GB', 'stateOrProvinceName': 'Greater Manchester', 'localityName': 'Salford', 'organizationName': 'COMODO CA Limited', 'commonName': 'COMODO RSA Certification Authority'}
2019-01-15 00:11:48,616,root,INFO,| written file ./bob.lumreeker@gmail.com.crt,bytes=1870,ok=True

为了快速验证,请查看最后一行 – 如果显示“written file”,那么您就很好了。其余部分展示了DKIM检查和证书验证过程。

我们将从这部分开始,因此在处理入站中继webhooks之前,我们要对其进行全面测试。

Web应用程序包含在与第1-3部分相同的GitHub项目中,因此如果您已经遵循了这些部分,那么您已经拥有它。以下是新的内容:

  • 程序 readSMIMEsig.py – 读取电子邮件并解析出中间和用户证书。

  • 程序 webapp.py – 简单的兼容Flask的web应用程序,用于配合SparkPost入站中继webhooks。

  • webapp.ini – 上述内容的配置文件。配置文件可以方便地将相同的值传递给命令行和web应用程序。

您需要确保您的主机的TCP端口号对外开放,以接收来自外部世界的入站请求,以便SparkPost可以将消息POST到您的应用程序。如果您托管在AWS EC2上,例如,您需要配置实例的安全组

配置和启动web应用程序的说明在我们的安装指南中提供 – 这很简单。要检查您的应用程序是否正在运行并可从外部访问,您可以使用curl从另一个主机发送(空白)请求,例如:

curl -X POST https://app.trymsys.net:8855/

您应该看到类似这样的响应:

{"message":"Unknown Content-Type in request headers"}

这是一件好事 – 您的应用程序正在运行!

在您主机的webapp.log中,您会看到类似这样的输出:

2019-01-15 00:11:07,575,root,INFO,Request from 38.96.5.10,scheme=https,path=/
2019-01-15 00:11:07,575,root,INFO,| len(headers)=3,len(body)=None
2019-01-15 00:11:07,575,root,INFO,| Unknown Content-Type: None

为了让您立即在应用程序中使用真实数据,您可以从项目存储库中导入这个特定的Postman请求。这模拟了您的SparkPost账户的行为,即发送包含特定有效证书(属于我的一个测试账户)的https POST到您的应用程序。

您只需更改请求中的目标地址(在上面的灰色框中)以匹配您的安装。如果您更改了webapp.ini中的token值,请调整Postman中的header值以匹配。

如果您的应用程序正常工作,您将在Postman中看到“200 OK”的响应。您的主机webapp.log文件将包含如下输出:

2019-01-15 00:11:48,554,root,INFO,Request from 38.96.5.10,scheme=https,path=/
2019-01-15 00:11:48,554,root,INFO,| len(headers)=10,len(body)=14778
2019-01-15 00:11:48,555,root,INFO,| msg_from=bob.lumreeker@gmail.com,rcpt_to=secureme@inbound.thetucks.com,len(email_rfc822)=9223
2019-01-15 00:11:48,599,root,INFO,| from=bob.lumreeker@gmail.com,DKIM passed
2019-01-15 00:11:48,600,root,INFO,| content-type=multipart/signed; protocol="application/pkcs7-signature"; micalg=sha-256; boundary="------------ms010908020707040304020406",content-description=None
2019-01-15 00:11:48,600,root,INFO,| content-type=text/plain; charset=utf-8; format=flowed,content-description=None
2019-01-15 00:11:48,600,root,INFO,| content-type=application/pkcs7-signature; name="smime.p7s",content-description=S/MIME Cryptographic Signature
2019-01-15 00:11:48,600,root,INFO,| filename=smime.p7s,bytes=3998
2019-01-15 00:11:48,601,root,INFO,| Certificate: subject email_address=['bob.lumreeker@gmail.com'],not_valid_before=2018-10-03 00:00:00,not_valid_after=2019-10-03 23:59:59,hash_algorithm=sha256,key_size=2048 bytes, issuer={'countryName': 'GB', 'stateOrProvinceName': 'Greater Manchester', 'localityName': 'Salford', 'organizationName': 'COMODO CA Limited', 'commonName': 'COMODO RSA Client Authentication and Secure Email CA'}
2019-01-15 00:11:48,602,root,INFO,| Certificate: subject email_address=[],not_valid_before=2013-01-10 00:00:00,not_valid_after=2028-01-09 23:59:59,hash_algorithm=sha384,key_size=2048 bytes, issuer={'countryName': 'GB', 'stateOrProvinceName': 'Greater Manchester', 'localityName': 'Salford', 'organizationName': 'COMODO CA Limited', 'commonName': 'COMODO RSA Certification Authority'}
2019-01-15 00:11:48,616,root,INFO,| written file ./bob.lumreeker@gmail.com.crt,bytes=1870,ok=True

为了快速验证,请查看最后一行 – 如果显示“written file”,那么您就很好了。其余部分展示了DKIM检查和证书验证过程。

我们将从这部分开始,因此在处理入站中继webhooks之前,我们要对其进行全面测试。

Web应用程序包含在与第1-3部分相同的GitHub项目中,因此如果您已经遵循了这些部分,那么您已经拥有它。以下是新的内容:

  • 程序 readSMIMEsig.py – 读取电子邮件并解析出中间和用户证书。

  • 程序 webapp.py – 简单的兼容Flask的web应用程序,用于配合SparkPost入站中继webhooks。

  • webapp.ini – 上述内容的配置文件。配置文件可以方便地将相同的值传递给命令行和web应用程序。

您需要确保您的主机的TCP端口号对外开放,以接收来自外部世界的入站请求,以便SparkPost可以将消息POST到您的应用程序。如果您托管在AWS EC2上,例如,您需要配置实例的安全组

配置和启动web应用程序的说明在我们的安装指南中提供 – 这很简单。要检查您的应用程序是否正在运行并可从外部访问,您可以使用curl从另一个主机发送(空白)请求,例如:

curl -X POST https://app.trymsys.net:8855/

您应该看到类似这样的响应:

{"message":"Unknown Content-Type in request headers"}

这是一件好事 – 您的应用程序正在运行!

在您主机的webapp.log中,您会看到类似这样的输出:

2019-01-15 00:11:07,575,root,INFO,Request from 38.96.5.10,scheme=https,path=/
2019-01-15 00:11:07,575,root,INFO,| len(headers)=3,len(body)=None
2019-01-15 00:11:07,575,root,INFO,| Unknown Content-Type: None

为了让您立即在应用程序中使用真实数据,您可以从项目存储库中导入这个特定的Postman请求。这模拟了您的SparkPost账户的行为,即发送包含特定有效证书(属于我的一个测试账户)的https POST到您的应用程序。

您只需更改请求中的目标地址(在上面的灰色框中)以匹配您的安装。如果您更改了webapp.ini中的token值,请调整Postman中的header值以匹配。

如果您的应用程序正常工作,您将在Postman中看到“200 OK”的响应。您的主机webapp.log文件将包含如下输出:

2019-01-15 00:11:48,554,root,INFO,Request from 38.96.5.10,scheme=https,path=/
2019-01-15 00:11:48,554,root,INFO,| len(headers)=10,len(body)=14778
2019-01-15 00:11:48,555,root,INFO,| msg_from=bob.lumreeker@gmail.com,rcpt_to=secureme@inbound.thetucks.com,len(email_rfc822)=9223
2019-01-15 00:11:48,599,root,INFO,| from=bob.lumreeker@gmail.com,DKIM passed
2019-01-15 00:11:48,600,root,INFO,| content-type=multipart/signed; protocol="application/pkcs7-signature"; micalg=sha-256; boundary="------------ms010908020707040304020406",content-description=None
2019-01-15 00:11:48,600,root,INFO,| content-type=text/plain; charset=utf-8; format=flowed,content-description=None
2019-01-15 00:11:48,600,root,INFO,| content-type=application/pkcs7-signature; name="smime.p7s",content-description=S/MIME Cryptographic Signature
2019-01-15 00:11:48,600,root,INFO,| filename=smime.p7s,bytes=3998
2019-01-15 00:11:48,601,root,INFO,| Certificate: subject email_address=['bob.lumreeker@gmail.com'],not_valid_before=2018-10-03 00:00:00,not_valid_after=2019-10-03 23:59:59,hash_algorithm=sha256,key_size=2048 bytes, issuer={'countryName': 'GB', 'stateOrProvinceName': 'Greater Manchester', 'localityName': 'Salford', 'organizationName': 'COMODO CA Limited', 'commonName': 'COMODO RSA Client Authentication and Secure Email CA'}
2019-01-15 00:11:48,602,root,INFO,| Certificate: subject email_address=[],not_valid_before=2013-01-10 00:00:00,not_valid_after=2028-01-09 23:59:59,hash_algorithm=sha384,key_size=2048 bytes, issuer={'countryName': 'GB', 'stateOrProvinceName': 'Greater Manchester', 'localityName': 'Salford', 'organizationName': 'COMODO CA Limited', 'commonName': 'COMODO RSA Certification Authority'}
2019-01-15 00:11:48,616,root,INFO,| written file ./bob.lumreeker@gmail.com.crt,bytes=1870,ok=True

为了快速验证,请查看最后一行 – 如果显示“written file”,那么您就很好了。其余部分展示了DKIM检查和证书验证过程。

3. SparkPost inbound relay webhooks 设置

首先,我们选择一个域名作为我们的入站消息地址——在这里,它将是 inbound.thetucks.com。按照这个指南设置你的域名。以下是我详细使用的步骤:

3.1 添加 MX 记录

你将需要访问你特定互联网服务提供商的账户。完成后,你可以用 dig 检查它们——这是我域的命令。

dig +short MX inbound.thetucks.com

你应该看到:

10 rx3.sparkpostmail.com. 10 rx1.sparkpostmail.com. 10 rx2.sparkpostmail.com

3.2 创建入站域

使用 SparkPost Postman API collection,选择 Inbound Domains / Create .. 调用。POST 请求的主体包含你的域,例如:

{ "domain": "inbound.thetucks.com" }
Postman desktop application with an open tab displaying a 'Create an Inbound Domain' API request, featuring fields such as domain input, several header options, and a JSON payload, aimed at testing and automating API workflows.


3.3 创建一个中继 Webhook

使用相关的 Postman 调用创建一个入站中继 webhook。在我的情况下,消息主体包含:

{
  "name": "Certificate Collection Webhook",
  "target": "https://app.trymsys.net:8855/",
  "auth_token": "t0p s3cr3t t0k3n",
  "match": {
    "protocol": "SMTP",
    "domain": "inbound.thetucks.com"
  }
}

如前所述,我建议设置一个 auth_token为你自己的秘密值,正如在你的主机上的 webapp.ini 文件中设置的那样。

你的“target”值需要匹配你的主机地址和托管 web 应用的 TCP 端口。

你的“domain”值需要匹配在步骤1中设置的 MX 记录。

Postman interface, showing the process of creating a relay webhook with detailed JSON configuration, with sections including request method, parameters, and code snippet.


就这样!管道已经完成。你现在应该能够将证书发送到你的入站地址,它们将被处理并显示在你的 web 应用程序主机上——在这个例子中,是一个名为 bob.lumreeker@gmail.com.crt 的文件。

现在你可以使用本系列第 2 & 3 部分描述的工具将加密邮件发送给 Bob。

你可以使用以下命令检查证书的内容:

openssl x509 -inform PEM -in bob.lumreeker\@gmail.com.crt -text -noout

4. Internals: DKIM 检查, 证书验证

该应用程序检查接收到的电子邮件是否具有有效的DKIM,并检查证书本身的有效性,如此处所述。 其中还有实现说明和进一步工作的想法。

总结…

我们已经看到如何使用电子邮件轻松收集收件人的公钥,这是通过转入中继webhooks地址完成的。完成后,这些收件人可以接收S/MIME加密形式的消息。

就到这里!发送愉快。

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

这个完整的AI原生平台可以随着您的业务进行扩展。

Product

解决方案

资源

Company

隐私设置

社交

Newsletter

通过每周更新到您的收件箱,随时了解 Bird 的最新动态。

Signup

© 2025 Bird

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

这个完整的AI原生平台可以随着您的业务进行扩展。

Product

解决方案

资源

Company

隐私设置

社交

Newsletter

通过每周更新到您的收件箱,随时了解 Bird 的最新动态。

Signup

© 2025 Bird