如何使用 Twilio SendGrid 和 Mezzio 使用 PHP 发送电子邮件
已发表: 2021-03-24电子邮件与以往一样重要,是一种沟通工具。 为了帮助您更好地利用电子邮件,我将向您展示如何使用 PHP 的 Mezzio 框架和 Twilio SendGrid 的 API 发送电子邮件。
具体来说,您将学习如何发送带有纯文本和 HTML 正文的电子邮件,其中包括 PDF 附件。 您还将学习如何使用 Twilio SendGrid 的事务模板功能来简化开发团队以及组织内的任何其他团队创建电子邮件正文的过程。
听起来不错? 让我们开始。
快速应用概述
作为使本教程更有意义的一种方式,假设我们将编写的代码是使用 Mezzio 构建的一个虚构的在线电子商务商店的一部分,名为The Little PHP Shop — 具体来说,是客户购买后的部分。 在用户流程中,客户会收到一封电子邮件,感谢他们的购买,并附上一份 PDF 发票以供记录。
我们将创建一个 Handler 类来发送购买后电子邮件,该电子邮件将从客户完成的订单中接收购买详细信息。 使用该购买信息,处理程序类将使用 SendGrid PHP API 中的几个类来构建和发送购买确认电子邮件。
其中,最重要的是“SendGrid\Mail\Mail”和“\SendGrid”。 “SendGrid\Mail\Mail”是存储我们将通过 Twilio SendGrid 发送的电子邮件消息的所有属性的对象。 “SendGrid”对象构成传输层,便于通过 Twilio SendGrid 发送电子邮件。
先决条件
要完成本教程,您需要在本地开发环境中完成以下 4 件事:
- Twilio SendGrid 帐户
- 安装并启用了cURL 、 mbstring和O pen SSL扩展的 PHP 7.4
- Composer全局安装
- 卷曲
搭建 Mezzio 应用程序
我们首先需要创建基础应用程序。 为此,我们将一如既往地使用Mezzio Skeleton为我们做这件事。 一旦我们搭建了基础应用程序,我们将切换到新创建的项目目录。 然后按照第一个提示在终端中运行以下命令:
安装所需的依赖项
随着项目的脚手架,我们需要添加 3 个额外的依赖项来完成项目。 这些是:
- Twilio SendGrid 的PHP API 库,用于与 Twilio SendGrid API 交互
- 用于发送 HTTP 请求的PHP HTTP 客户端
- PHP Dotenv用于存储和检索环境变量
要安装它们,请在终端中运行以下命令:
初始化 PHP Dotenv
安装依赖项后,我们加载 PHP Dotenv,以便它读取“.env”中设置的变量并将它们作为环境变量提供给 PHP。 为此,在“public/index.php”中插入以下代码,就在“require vendor/autoload.php”之后。
添加您的 Twilio SendGrid 帐户详细信息
现在您需要为应用程序提供您的 SendGrid API 密钥。 为此,在登录Twilio SendGrid后,导航到“设置 -> API 密钥”。 ” 一旦出现:
- 单击“创建 API 密钥”以创建 API 密钥
- 为新的 API 密钥命名,接受默认的 API 密钥权限“完全访问” ,然后单击“创建和查看”
创建 API 密钥后,单击并复制密钥,然后单击“完成” 。 ”
之后,再向文件添加 2 个键:“SENDGRID_DEFAULT_SENDER_ADDRESS”和“SENDGRID_DEFAULT_SENDER_NAME”。 正如名称所示,这些是我们将用于从我们的应用程序发送的任何电子邮件的电子邮件地址和名称,除非被覆盖。
注意:为此,在Sender Authentication中,确保它在“Single Sender Verification”表中显示“Verified”。
设置应用程序邮件配置详细信息
除了 Twilio SendGrid API 密钥之外,我们还将存储一些其他全局邮件配置设置。 具体来说,我们将设置一个发件人并回复电子邮件地址和名称,我们将在每封电子邮件中使用它们。 这样,我们不必每次都设置它们。
我们还将创建 2 个电子邮件正文模板:一个用于纯文本电子邮件,一个用于 HTML 电子邮件。 为此,在“config/autoload”中创建一个名为“mail.global.php”的新文件,并在其中添加以下代码。
创建一个类来实例化一个邮件对象
设置关键应用程序配置详细信息后,现在让我们创建一个类,该类将使用默认属性集实例化一个基本邮件对象。 为此,在一个新目录“src/App/src/Mailer”中,创建一个名为“SendGridMailMessageFactory.php”的新文件,并在其中添加以下代码。
当我们调用该类时,它可以访问应用程序的依赖注入 (DI) 容器,从中检索我们存储在“config/autoload/mail.global.php”中的配置详细信息。
之后,它将实例化一个新的“SendGrid\Mail\Mail”对象,并通过将各自的配置详细信息分别传递给“Mail”、“setFrom”和“setReplyTo”方法的调用来设置发件人和回复详细信息。 之后,它将返回实例化的“Mail”对象。
但是,要使用它,您必须在 DI 容器中注册它。 为此,在“src/App/src/ConfigProvider”中,将以下条目添加到“getDependencies”方法返回的数组中的“factories”元素中。
创建一个处理程序来发送电子邮件
接下来我们需要创建一个 Handler 类来编写和发送电子邮件。 为此,我们将使用Mezzio 的 CLI 工具(可通过 Composer 获得),方法是运行以下命令。
运行上面的命令为我们做了四件事:
- 创建一个新的处理程序类,“src/App/Handler/EmailSenderHandler.php ”
- 创建一个工厂类来实例化 Handler 类,“src/App/Handler/EmailSenderHandlerFactory.php”
- 创建一个我们不需要的模板文件(“src/App/templates/app/email-sender.html.<ext>”) 。 文件名“<ext>”由您在“create-project”阶段选择的模板引擎决定。
- 通过向“config/autoload/mezzio-tooling-factories.global.php”添加条目,将新的 Handler 类注册为 DI 容器中的服务
重构处理程序以发送电子邮件
创建“EmailSenderHandler.php”后,我们现在需要对其进行重构,以便它可以发送电子邮件。 为此,我们将首先重构“EmailSenderHandler”的构造函数,将“TemplateRendererInterface”参数替换为 3 个新参数。 这些将初始化 3 个新的类成员变量:
- “\SendGrid\Mail\Mail”对象
- 一个“\SendGrid”对象
- 包含所需配置详细信息的数组
您可以在下面的示例中看到修改后的构造函数,以及相关的类成员变量。 用此代码替换现有的类成员变量和构造函数。
注意:接下来,我们需要重构“handle”方法。 将“EmailSenderHandler”“handle”方法的现有内容替换为下面的代码,然后让我们逐步了解它的作用。
它首先使用“$request->getParsedBody()”来检索请求正文中提供的任何参数,这将返回一个关联数组,初始化“$details”。 使用可用的参数,它调用“SendGrid\Mail\Mail”对象的“addTo”方法来设置电子邮件的收件人,在前两个参数中传入收件人的电子邮件地址和姓名,在第三个参数中传递一个替换数组。
替换允许您为每个收件人自定义电子邮件消息。 在纯文本电子邮件中,任何直接被连字符包围的字符串,例如“-first_name-”都是替换。 在 HTML 电子邮件中,它使用Handlebars 语法,用双括号括住字符串,例如“{{ first_name }}”。
接下来,我们设置消息的主题并添加纯文本和 HTML 消息正文。 这样,我们的电子邮件就可以发送了。 因此,我们使用“SendGrid”对象“$this->mailer”来发送它,初始化一个新变量“$response”,其中包含尝试发送消息的响应。 最后,我们返回一个 JsonResponse 对象,其中包含响应的状态代码和正文。
注意:重构 EmailSenderHandlerFactory 的 __invoke 方法
现在我们已经完成了“EmailSenderHandler”的重构,我们需要重构“EmailSenderHandlerFactory”。 这将正确地实例化“EmailSenderHandler”。 为此,请将其“__invoke`”方法的现有定义替换为以下代码。
这会从 DI 容器中检索“\SendGrid\Mail\Mail”对象,使用发件人预初始化并回复电子邮件详细信息,并初始化一个名为“$message”的新对象。 然后它实例化一个名为“$mailer”的新“SendGrid”对象,用于发送邮件消息。 最后,它从应用程序的配置中检索邮件配置。 然后,它使用这些来初始化并返回“EmailSenderHandler”对象。
更新路由表
通过所有这些更改,在我们可以测试代码并发送电子邮件之前,还需要进行最后一项更改。 我们必须更新路由表,以便默认路由使用我们新的 Handler 类作为路由的处理程序,而不是“HomePageHandler”。 为此,请将“config/routes.php”中的默认路由定义替换为以下示例。
发送第一封电子邮件
现在是发送第一封电子邮件的时候了。 为此,首先,通过在终端中运行以下命令来启动应用程序。
然后,使用 cURL 向“ http://localhost:8080 ”发出 GET 请求,如下例所示,将尖括号中的值替换为电子邮件的相关详细信息。
您应该会看到“{“status”:202,“message”:””}” 输出到终端,并且您应该收到一封如下图所示的电子邮件。
注意:请使用事务性电子邮件模板而不是模板字符串
虽然我们已经能够发送包含纯文本和 HTML 正文的电子邮件,但是我们如何做到这一点并不理想。 对于我们发送的每封电子邮件——我们的应用程序最终可能会发送很多——我们需要为它们添加纯文本和 HTML 正文。
但是将电子邮件正文定义存储在代码中会将大部分精力放在开发团队身上。 但是,至少根据我的经验,其他团队(通常是营销团队)通常会创建和维护电子邮件模板。
因此,出于这个原因,并且因为它会加快开发速度并在多个团队之间分担负载,我们将重构应用程序以使用事务性电子邮件模板。 您可以通过 Twilio SendGrid UI 由可能很少或没有技术经验的团队成员创建和维护这些,而不是在代码中。
如果您没有听说过它们, Twilio SendGrid 词汇表将它们定义如下:
交易电子邮件模板是预编码的电子邮件布局,营销人员、设计师和开发人员可以使用它来快速轻松地创建交易电子邮件活动。 Twilio SendGrid 的事务性电子邮件模板允许非技术人员和技术人员对收件人收到的电子邮件进行实时更改。
对于本文,我们只需要一个相当基本的。 为此,请遵循Twilio SendGrid 文档中的详细信息,并创建一个仅在单个文本模块中作为其内容的内容。 然后,对于正文,使用下面的文本。
请注意,电子邮件中有 6 个替换项:
- “first_name”:客户的名字
- “last_name”:客户的姓氏
- “sender_name”:电子商务商店的名称(The Little PHP Shop)
- “sender_state”:电子商务商店的状态
- “sender_country”:电商所在国家
- “support_email”:客户可以用来获得售后支持的支持电子邮件
鉴于此,我们需要将该信息提供给我们的应用程序。 我们已经有了客户的名字和姓氏。 剩下的 4 个替换将是全局的,所以就像我们之前所做的那样,我们将在“templates”元素之后将下面的配置添加到“ config/autoload/mail.global.php ”中。
创建新配置文件后,在“EmailSenderHandler”“handle”方法中,用以下代码替换对“$this->mail->addContent()”的 2 次调用。
2 个方法调用添加发件人详细信息并支持电子邮件地址作为全局替换。 这些替换在任何其他替换之前适用于电子邮件正文,但如果存在具有相同密钥的电子邮件收件人的替换,则这些替换将被覆盖。
接下来,您需要检索事务性电子邮件模板的 ID。 您可以通过单击模板列表中的模板名称来找到它,如下面的屏幕截图所示。
复制它并将其存储在“config/autoload/mail.global.php”中的新元素中,键为“template_id”,然后删除“plain”和“HTML”。 完成后,返回数组的“mail/templates”元素将如下面的代码所示,其中“<the template's id>”替换了模板的 ID。
更新配置后,我们现在需要在“EmailSenderHandler”“handle”方法中添加对“Mail”“setTemplateId”方法的调用,传入我们刚刚添加到“config/autoload/mail.global”的模板 ID。 php。” 您可以在下面的代码中看到一个示例。
让我们测试一下更改
和以前一样,使用 cURL 向“ http://localhost:8080 ”发出 GET 请求,以测试更改是否按预期工作。 您应该会看到“{“status”:202,“message”:””}” 输出到终端,如前面的示例所示。 在您的电子邮件收件箱中,您应该会看到一封可爱的电子邮件,其中替换了替换内容,如下面的屏幕截图所示。
附上 PDF 发票
现在我们正在使用动态模板,让我们附上我们在文章顶部讨论过的 PDF 发票。 为了节省您自己查找或创建发票的时间和精力,我创建了一个示例 PDF 发票,您可以在本文中使用它。 将其保存在应用程序的“数据”目录中。
注意:要附加发票,我们需要使用“Mail”“addAttachment”方法,您可以在下一个代码示例中看到该方法。 该方法需要 5 个参数,但我们只提供前 4 个参数。它们是:
- “附件”对象或Base64 编码字符串。 如果此参数的值不是 base64 编码的,则该方法将为我们执行此操作。
- 附件的 MIME 类型(现在称为媒体类型)。
- 附件的文件名。 这是文件默认保存的名称,除非用户更改它。
- 附件的内容处置。 如果您不熟悉 content-disposition,则inline content-disposition 意味着附件应在消息显示时自动显示,而attachment content-disposition 意味着附件不会自动显示并且需要用户采取某种形式的操作打开它。
在下面的代码示例中,PHP 的file_get_contents方法将文件的内容读入名为“$invoice”的新变量中。 然后,PDF 通过调用“addAttachment”方法附加到消息中。
在这里,我们:
- 传入发票的内容,这将是 Base64 编码的
- 附加 PDF 文件时,将 MIME 类型设置为“application/pdf”
- 将发票的文件名设置为客户可能合理预期的虚构名称
- 将内容处置设置为“附件”
现在我们已经完成了这些更改,让我们测试它们是否有效。 运行与前 2 次相同的 cURL 请求。 然后,在您的电子邮件收件箱中,您应该会看到一封精美的电子邮件,其中包含在查看电子邮件时可见的示例 PDF 发票。
这就是使用 Twilio SendGrid 和 Mezzio 使用 PHP 发送电子邮件的方法
虽然我们只触及了使用 Twilio SendGrid 和 Mezzio 发送电子邮件时可能实现的功能的表面,但您现在可以发送带有纯文本和 HTML 正文以及附件的电子邮件。 您还学习了如何使用可以全局设置且基于每个收件人的事务模板和替换。
我强烈建议您查看PHP 库的文档以了解其他可用的内容,例如安排电子邮件发送、附加来自 Amazon S3 的文件、添加标题以及添加部分和类别。
Matthew Setter 是 Twilio Voices 团队的一名 PHP 编辑器,当然也是一名 PHP 开发人员。 他也是Mezzio Essentials的作者。 当他不编写 PHP 代码时,他正在 Twilio 编辑优秀的 PHP 文章。 可以通过以下方式联系到他:
- 电子邮件: [email protected]
- 网址: http: //matthewsetter.com
- 推特: @settermjd
- GitHub: https://github.com/settermjd