卓越飞翔博客卓越飞翔博客

卓越飞翔 - 您值得收藏的技术分享站
技术文章16428本站已运行3317

扩展 Drupal 8 Mail API 的功能:第 1 部分

扩展 Drupal 8 Mail API 的功能:第 1 部分

在这两个部分的系列中,我们将探索 Drupal 8 中的邮件 API。在此过程中,我们将涵盖两个主要方面:如何以编程方式使用它来发送电子邮件以及如何扩展它以使用外部像山魈一样的服务。

为了演示这一点,在第一部分中,我们将创建一个自定义电子邮件模板,用于在当前用户保存新的文章节点时向他/她发送电子邮件。此外,我们将了解其他人如何更改该模板,以便允许 HTML 呈现电子邮件正文而不是默认的纯文本。

在第二部分中,我们将研究扩展邮件系统并集成外部 API 以进行电子邮件传送。为此,我们将使用 Mandrill 及其 PHP 库,它为与其 API 交互提供了良好的基础。

我们完成的所有工作都可以在这个 Git 存储库中找到,作为我们将在这里开始编写的自定义 Drupal 8 模块的一部分。因此,如果您想继续了解,请随时查看。让我们开始吧。

该模块的第一个先决条件是它的 .info 文件:

d8mail.info.yml

name: Drupal 8 Mailer
description: 'Demonstrates the use of the Mail API in Drupal 8.'
core: 8.x
type: module

解决了这个问题,我们就可以根据需要在我们的网站上启用该模块。

我们如何发送电子邮件?

使用 Drupal 8 以编程方式发送电子邮件需要两个主要步骤。我们首先需要实现 hook_mail() 来定义一个或多个电子邮件模板。第二步是使用邮件管理器使用这些模板之一发送电子邮件。

虽然称为钩子,但 hook_mail() 并不是典型的钩子,而是更多的常规函数​​,通常仅由实现它的同一模块调用。换句话说,当您以编程方式发送电子邮件时,您需要指定实现 hook_mail() 的模块名称以及您想要使用且由该挂钩定义的模板 id。但我们很快就会看到这一点。首先,我们如何实现它?

d8mail.module

/**
 * Implements hook_mail().
 */
function d8mail_mail($key, &$message, $params) {
  $options = array(
    'langcode' => $message['langcode'],
  );

  switch ($key) {
    case 'node_insert':
      $message['from'] = \Drupal::config('system.site')->get('mail');
      $message['subject'] = t('Node created: @title', array('@title' => $params['node_title']), $options);
      $message['body'][] = SafeMarkup::checkPlain($params['message']);
      break;
  }
}

这是一个非常简单的实现,定义了一个标识为 node_insert$key)的模板。另外两个函数参数是:

  • $message:通过引用传递,在其中我们根据需要添加尽可能多的有关电子邮件的样板
  • $params:需要放入电子邮件中的额外数据数组,当我们尝试发送电子邮件时从邮件管理器传递该数组

如您所见,我们正在构建 $message 数组,其中包含我们希望此电子邮件包含在所有调用中的值。我们正在设置一个默认的 from 值,该值从配置系统检索并代表主站点电子邮件地址。我们设置一个样板电子邮件 subject ,让收件人知道创建了一个新节点,后跟节点的名称(将通过 $params 数组传入)。该主题也可以翻译成从调用者那里传递的语言。

最后,我们通过字符串清理程序运行消息 body,因为文本可能包含 HTML,如果我们不对 HTML 元素进行编码,它可能会被截断。由于我们使用的是 SafeMarkup 类,因此我们需要在顶部使用它:

use Drupal\Component\Utility\SafeMarkup;

此外,消息正文是一个数组,稍后将内爆为字符串。显然我们还可以设置许多其他参数,例如标头,但这对于本示例来说就足够了。

这就是 hook_mail() 实现的全部内容。现在让我们看看每次创建新节点时运行的代码,hook_entity_insert():

/**
 * Implements hook_entity_insert().
 */
function d8mail_entity_insert(Drupal\Core\Entity\EntityInterface $entity) {

  if ($entity->getEntityTypeId() !== 'node' || ($entity->getEntityTypeId() === 'node' && $entity->bundle() !== 'article')) {
    return;
  }

  $mailManager = \Drupal::service('plugin.manager.mail');

  $module = 'd8mail';
  $key = 'node_insert';
  $to = \Drupal::currentUser()->getEmail();
  $params['message'] = $entity->get('body')->value;
  $params['node_title'] = $entity->label();
  $langcode = \Drupal::currentUser()->getPreferredLangcode();
  $send = true;

  $result = $mailManager->mail($module, $key, $to, $langcode, $params, NULL, $send);
  if ($result['result'] !== true) {
    $message = t('There was a problem sending your email notification to @email for creating node @id.', array('@email' => $to, '@id' => $entity->id()));
    drupal_set_message($message, 'error');
    \Drupal::logger('d8mail')->error($message);
    return;
  }

  $message = t('An email notification has been sent to @email for creating node @id.', array('@email' => $to, '@id' => $entity->id()));
  drupal_set_message($message);
  \Drupal::logger('d8mail')->notice($message);
}

这个钩子在每次节点保存后都会被触发,我们所要做的就是确保我们瞄准正确的节点并包含我们的逻辑。

检查节点实体的类型为 article 后,我们加载 Drupal 邮件管理器服务并开始为电子邮件设置一些值。我们需要以下信息:

  • 实现 hook_mail() 并定义我们的模板(我上面提到的)的模块名称
  • 模板 ID($key
  • 收件人电子邮件地址(在当前用户帐户中找到的地址)
  • 进入 $params 数组并用于翻译主题消息的语言 ($langcode)
  • 将添加到电子邮件主题的节点标题
  • 电子邮件正文,在我们的例子中将是节点正文字段的值
  • 指示是否应实际发送电子邮件的布尔值

然后我们将所有这些值传递给邮件管理器的 mail() 方法。后者负责构建电子邮件(调用正确的 hook_mail() 实现是其中的一方面)并最终将实际交付委托给负责的插件。默认情况下,这将是 PHPMail,它使用 PHP 自带的默认 mail() 函数。

如果邮件管理器成功发送电子邮件(不考虑实际发送,而是考虑成功的 PHP 操作),则 mail() 方法将返回一个包含 result 键的数组,其中包含以下内容:邮件插件返回。通过检查该值,我们可以了解电子邮件操作是否成功,并通知用户我们已通知他们他们的操作。否则,我们将打印并记录一条错误消息。

就是这样。清除缓存并创建文章节点应该会在您的收件箱中收到一封电子邮件。如果您没有收到任何信息,并且屏幕上没有错误迹象,请务必检查服务器日志和邮件队列,以验证电子邮件是否已发出。

在继续之前,我想快速说明一下这个钩子的实现。在这个例子中,我直接将所有逻辑放在其中。此外,我在顶部使用了早期返回,这本质上意味着除了特定于文章节点的逻辑之外,不能添加其他逻辑。在实际应用程序中,我建议将邮件逻辑重构为单独的函数或类,并遵循该逻辑。此外,您不应在钩子实现中使用提前返回,而应在满足条件时调用其他函数。

我们如何更改电子邮件?

一旦所有这些都到位,我们就可以使用另一个工具来更改现有的设置:hook_mail_alter()。在负责的邮件插件发送电子邮件之前,从邮件管理器内部调用此挂钩。目的是允许其他模块对正在发送的现有电子邮件进行最终更改。

虽然其他模块也可以使用它,但我们将在我们一直使用的同一模块中说明示例实现。为此,我们将通过更改其默认标头之一来更改电子邮件,以便将其从纯文本转换为 HTML。我们可以这样做:

/**
 * Implements hook_mail_alter().
 */
function d8mail_mail_alter(&$message) {
  switch ($message['key']) {
    case 'node_insert':
      $message['headers']['Content-Type'] = 'text/html; charset=UTF-8; format=flowed; delsp=yes';
      break;
  }
}

如您所见,这是对 Content-Type 标头的简单更改,可将电子邮件转换为 HTML。这样纯文本 HTML 实体将被邮件客户端解析为 HTML。使用 switch case,我们确保这只发生在我们之前定义的电子邮件模板中。

这里需要注意的一件事是,在相关的 hook_mail() 实现之后调用 alter hook。因此,在此之后,对电子邮件进行的唯一处理是在邮件插件的 format() 方法内完成的(由其接口强制执行)。

结论

这几乎就是使用 Drupal 8 以编程方式发送电子邮件的全部内容。我们已经了解了以编程方式设置电子邮件模板所需的步骤,只要我们需要,这些模板就会由邮件管理器进行水合。我们还提到了 Drupal 8 中用于发送电子邮件的默认邮件传递插件。最后,我们看到了其他模块现在如何通过添加新标头、更改主题、将值连接到邮件正文来更改我们的电子邮件等

在下一篇文章中,我们将考虑用我们自己的自定义实现替换默认的 PHPMail 插件。我们将在 PHP 库的帮助下设置一个使用 Mandrill 的邮件程序。目标是允许我们自己的模块使用此邮件程序,而应用程序的其余部分继续使用默认的 PHPMailer。

卓越飞翔博客
上一篇: 将N表示为K个非零整数的不同方式
下一篇: 返回列表
留言与评论(共有 0 条评论)
   
验证码:
隐藏边栏