如何使用 Python 的 Flask 框架接收电子邮件
已发表: 2020-04-30虽然 Internet 上有很多关于发送电子邮件的教程,但关于如何配置应用程序来接收和处理它们的教程却很少。 如果您尝试自己设置所有内容,这是一项非常困难的任务,但使用 Twilio SendGrid 的入站解析功能时,它就像接收 Web 请求一样简单。
在这个简短的教程中,您将学习如何使用 Python 和 Flask Web 框架让 Twilio SendGrid 将您的电子邮件直接转发到您的 Web 应用程序。
要求
这些是完成本教程的要求:
- Python 3:如果您的操作系统不提供 Python 3 解释器,您可以前往python.org下载安装程序。
- Twilio SendGrid 帐户:如果您是 Twilio SendGrid 的新手,您可以创建一个免费帐户,它允许您每天永远发送 100 封电子邮件。
- 您将在其上接收电子邮件的域:在本文中,我将使用yourdomainhere.com 。 您需要将其替换为您自己的域名。
- ngrok :我们将使用这个方便的实用程序将您计算机上本地运行的 Flask 应用程序连接到 SendGrid 可以向其发送请求的公共 URL。 这对于应用程序的开发版本是必要的,因为您的计算机可能位于路由器或防火墙后面,因此无法在 Internet 上直接访问它。 如果您没有安装 ngrok,您可以下载适用于 Windows、MacOS 或 Linux 的副本。
域认证
在 Twilio SendGrid 可以接受您域上的电子邮件之前,您必须对其进行身份验证,以便 Twilio SendGrid 知道该域在您的控制之下。
启动域认证
要验证您的域,请登录您的 SendGrid 帐户,然后在左侧导航栏中打开“设置”,然后选择发件人验证。
在发件人身份验证页面中,单击“域身份验证”部分中的“开始”按钮。
系统将要求您选择 DNS 提供商,在大多数情况下,该提供商与您购买域的公司相同。 如果您的 DNS 提供商未出现在列表中,或者您不知道他们是谁,只需选择“我不确定”。
然后,系统会询问您是否为外发电子邮件中出现的链接添加品牌。 这不是我们目前关心的话题,所以选择“否”。 如果您想使用它,您可以在以后启用此选项。
单击“下一步”按钮继续到下一页。
在接下来的页面中,您将被要求提供您的域名。 我输入了yourdomainhere.com ,您需要输入您打算使用的域。 您无需更改“高级设置”部分中的任何内容。
单击“下一步”按钮继续。
该页面现在将显示 3 个您需要添加到域配置中的新 DNS 记录,每个记录都有一个类型、一个主机名和一个值。 为方便起见,主机和值都可以复制到剪贴板。 您可以在下面看到我给出的设置。 您的将是相似的,但其中包含您自己的域名:
将 DNS 条目添加到您的域
下一步将根据您的 DNS 提供商而有所不同。 访问您的域的配置页面并找到编辑 DNS 设置的位置。
下面的屏幕截图适用于Google Domains 。 您可以在下图中看到我如何添加三个 DNS 记录中的第一个。 请注意,名称为@、 ftp和www记录的 3 条记录与本教程无关,并且已在我的域中设置。
请注意输入 DNS 记录名称的方式。 虽然一些提供商希望您的 DNS 记录有一个完全限定的名称,如 SendGrid 所示,但其他提供商只希望域名之前的部分。 例如,SendGrid 显示为em3329.yourdomainhere.com的记录必须在 Google Domains 上输入为em3329 。 检查您的其他 DNS 记录,并在输入这些新记录时保持一致。
以下是我输入 3 条新 DNS 记录后的样子:
域验证
现在返回到 SendGrid发件人身份验证页面,您的域将显示为待处理。 单击它以继续进行身份验证过程。
在下一个屏幕中,您将看到 3 条 DNS 记录。 单击页面右上角的“验证”按钮,让 SendGrid 提取您的 DNS 记录并确认您已添加请求的条目。
如果 SendGrid 能够验证您的域,您将获得“成功!” 页:
另一方面,如果 SendGrid 无法验证您的 DNS 条目,您将需要稍后再试。 每次进行 DNS 更改时,更改在 DNS 服务器之间传播都需要一些时间。 编辑 DNS 条目后立即失败仅意味着您需要再给它一点时间,然后再点击“验证”按钮。 请注意,DNS 完全传播最多可能需要 48 小时,但通常需要的时间要少得多。
一旦你得到“它成功了!” 页面,您正在顺利将电子邮件发布到您的 Flask Web 应用程序。
Flask 电子邮件应用程序
现在我们准备编写一个简单的 Flask Web 应用程序,SendGrid 可以在其中转发我们的电子邮件。
创建 Python 虚拟环境
遵循 Python 最佳实践,我们将为我们的项目创建一个单独的目录,并在其中创建一个虚拟环境。 然后我们将在其上安装 Flask 框架。
如果您使用的是 Unix 或 Mac OS 系统,请打开终端并输入以下命令来执行上述任务:
如果您在 Windows 上遵循本教程,请在命令提示符窗口中输入以下命令:
传入电子邮件路由
现在让我们编写一个接收传入电子邮件的 Flask 应用程序。 完整应用程序的代码如下所示。 将此代码放在名为app.py的文件中。
该应用程序只有一个连接到/email URL 的 Web 路由。 我们将让 SendGrid 调用此路由以将传入的电子邮件传递给我们。 他们发送的请求将包含与作为标准 HTTP 表单帖子发送的电子邮件相关的所有详细信息。 这意味着我们可以从 Flask 轻松地从 `request.form` 字典中访问所有这些详细信息。
以下表单变量特别有趣:
- `request.form['from']`:电子邮件的发件人
- `request.form['to']`:电子邮件的收件人
- `request.form['subject']`:电子邮件主题
- `request.form['text']` 纯文本格式的电子邮件正文
- `request.form['html']` HTML 格式的电子邮件正文
请注意,这些不是 SendGrid 提交的唯一字段。 查看SendGrid 文档中的完整电子邮件参数列表。
由于处理电子邮件很大程度上依赖于每个应用程序,对于示例 Flask 应用程序,我们所做的就是将电子邮件字段打印到控制台。
保存app.py后,您可以按如下方式启动 Flask 应用程序:
该应用程序现在正在运行并侦听传入的请求,但只能从您自己的计算机访问。 暂时让应用程序在您的终端窗口上运行。 在下一节中,我们将把它公开给 Internet。
SendGrid 入站解析 webhook
本教程的最后一部分是配置 SendGrid 以将您域中的传入电子邮件转发到 Flask 应用程序。
开始 ngrok
ngrok 工具创建一个公开可用的 URL 并将其映射到本地运行的应用程序。 这是用于在 Internet 上公开服务以进行开发和测试的常用技术。 一旦您的 Flask 应用程序完成,您将在适当的服务器上部署它以进行生产,这将不再需要。
如果您还没有,请在您的系统上安装ngrok 。 保持 Flask 应用程序运行并打开第二个终端窗口以启动 ngrok,如下所示:
这告诉 ngrok 创建一个从公共 Internet 到我们本地计算机的端口 5000 的“隧道”,Flask 应用程序正在等待 Web 请求。 ngrok 的输出将如下所示:
注意 ngrok 屏幕中以“Forwarding”开头的行。 这些显示了一个随机生成的公共 URL,ngrok 使用该 URL 将请求重定向到我们的服务。 我们将使用https:// URL,因为它使用加密。
使用 SendGrid 注册 webhook URL
返回到SendGrid 仪表板,在 Settings 下选择Inbound Parse ,然后单击“Add Host & URL”。
在下一页中,输入您将在其上接收电子邮件的子域。 这可以是您的域上尚未使用的任何子域,或者如果您希望直接在顶级域上接收电子邮件,则可以将其留空。 在下图中,我使用了子域parse ,这意味着 SendGrid 接受的电子邮件将具有格式 < any>@parse.yourdomainhere.com 。 将子域字段留空将允许 SendGrid 接受<anything>@yourdomainhere.com的电子邮件,这在某些情况下可能更可取。
接下来您必须选择您的域名。 这是一个下拉列表,显示您已使用 SendGrid 验证的所有域。 如果您是第一次这样做,您将只会看到您之前验证过的域。
以下字段用于您的 webhook的目标 URL 。 这是由 ngrok 生成的 URL,附加了 Flask URL /email 。 就我而言,这是https://bbf1b72b.ngrok.io/email 。 您将有一个类似的 URL,但 ngrok 主机名的第一部分将有所不同。
单击“添加”以配置您的 webhook。
现在,您将在 Inbound Parse 主页面中看到您的 webhook 的条目:
注意:每次 ngrok 停止和重新启动时,ngrok URL 都会更改,因此在开发过程中,您需要编辑 webhook 以在每次重新启动 ngrok 时更新 URL。 当您部署 webhook 以供生产使用时,您将直接将其托管在公共 URL 上,因此不会使用 ngrok。
注册解析子域
您在上一节中选择接收电子邮件的子域需要在您的域的 DNS 配置中使用“MX”记录进行定义。 此记录的值对于所有 SendGrid 客户都是相同的:`mx.sendgrid.net.`(注意“net”后面的尾随点)。
在我的 Google Domains DNS 配置中,我将解析子域定义如下:
回想一下,根据您使用的域提供商,您可能需要输入此 DNS 记录的完整主机名,因此在这种情况下,它将是parse.yourdomainhere.com 。
如果您决定在上一节中不定义子域,那么您的主机名将是yourdomainhere.com ,对于某些 DNS 提供商,必须以“ @”形式给出。
请记住,此 DNS 更改也需要传播,因此您可能无法立即接收电子邮件。
发送测试电子邮件
当您的 Flask 应用程序和 ngrok 都在运行时,打开您的电子邮件客户端并发送一封测试电子邮件。 在“收件人:”字段中,您可以输入您想要的任何用户名,因为 SendGrid 会捕获所有用户名。 @ 之后的内容必须是您完整的电子邮件接收域。
在下面的示例中,我向[email protected]发送了一封电子邮件:
等待一两分钟让 SendGrid 接收电子邮件并将其转发到 ngrok webhook URL,然后将其传递到 Flask 的/email端点。 正如您在上面看到的,我在 Flask 应用程序中编写的简单端点将收到的电子邮件数据打印到控制台:
就是这样,我们现在在 Flask 应用程序中以 Web 请求的形式接收电子邮件!
生产部署
在本节中,我想指出在开发期间部署的 webhook 和那些用于生产的 webhook 之间的几个重要区别。
没有 ngrok 的部署
如上所述,ngrok 不是生产工具,永远不应该在生产部署中使用。 相反,您将在直接连接到 Internet 的服务器上部署 Flask 应用程序。 Flask 文档中讨论了几个部署选项。
Webhook 安全性
考虑到您的电子邮件接收端点在 Internet 上公开可用,因此知道 URL 的任何人都可以向它发送请求,这可能会使您的应用程序暴露于伪装成 SendGrid 请求的恶意用户发送的虚假调用。
防止此类攻击的一个好方法是在 Flask 端点上实现基本身份验证。 Flask-HTTPAuth扩展有助于实现这种类型的安全性。
如果向端点添加身份验证,则需要在提供给 SendGrid 的 webhook URL 中包含用户名和密码。 我上面使用的 webhook 必须以https://username:[email protected]/email 的形式给出。
结论
尽管设置所有内容以接收电子邮件涉及很多步骤,但这是实现它的最简单方法之一。 有关入站解析的更多信息,请查看我们的文档页面。
我们迫不及待地想看看您使用 Inbound Parse 构建的内容!