Drupal 8: Отправка HTML писем через Contact

04.09.2016

Изначально я хотел просто разобраться с модулем Contact, написать как править формат писем которые он отправляет, я конечно же полез в ядро, и там особо не разгуляться. HTML письма отправлять нельзя, без дополнительного альтера, максимум текст подправить, поэтому я решил влезть в тему поглубже и нашел куда более мощное решение. Но если вам хочется все делать руками и через код, то в поможет вам hook_mail_alter() и функция, которая отвечает за подготовку писем модуля Contact - contact_mail(). В общем все как и в D7. Вы также можете получать значения кастомных полей вот так: $contactMessage = $message['params']['contact_message']; и $contactMessage->get('field_name')->getString();

А я расскажу о более комплексном подходе, потому что, как мне кажется, он будет более востребован и необходим. Я начал изучать как дела обстоят в 8-ке, и если в Drupal 7 для отправки HTML писем, как правило, используется Mime Mail, то в Drupal 8 ситуация совершенно иная. Тут все рекомендуют использовать Swift Mailer - как оказалось, это небольшая библиотека для PHP чтобы отправлять письма от SensioLabs, тех что создали Symfony и Twig, которые активно используются в Drupal 8. Так что даже логично, юзать либу из одной экосистемы, и к этим ребятам есть доверие. Соответственно модуль лишь обвязка для библиотеки которое позволит использовать все её возможности, но об этом попозже.

Улучшение модуля Contact

Contact Storage - невероятно полезный модуль если вы собираетесь использовать Contact из ядра. Я вообще не понимаю, как так получилось что такого функционала не оказалась в ядре вместе с самим Contact. Он настолько очевидный и необходимый, при этом это по сути функционал Entifyform. Раз уже сделали его аналог в ядре, почему бы сразу не допилили до ума. Данный модуль раскрывает Contact полноценно как формы-сущности, побуду немного гадалкой и сказу что его потом и внедрят в ядро. Причем на его странице прямо и написано, что цель - попасть в ядро. Что же добавляет данный модуль:

  • Позволяет отправлять письма в формате HMTL.
  • Хранение всех отправленных сообщений на сайте. Это очень круто! Ведь никакой сбой или проблемы с почтой не потеряют письмо, он продублируется и на сайте. Разумеется с возможностью редактировать и удалять их.
  • Возможность указать свой путь для редиректа после успешной отправки формы.
  • Также позволяет указать свой алиас пути для страницы отправки формы, чтобы не пользать на страницу управления алиасами.
  • Позволяет одной галочкой отключать кнопку Preview.
  • Позволяет ограничить количество отправлений через форму для пользователей.
  • Добавляет возможность клонировать формы.

Установка необходимых модулей

А теперь вернемся непосредственно к письмам. Для дальнейшей работы нам понадобятся следующие модули Mail System, Swift Mailer и Contact Storage. Обращаю внимание сразу на то, что Swift Mailer нужно (!) ставить через composer иначе он просто не будет работать.

composer require drupal/swiftmailer:~1.0

Настройка Swift Mailer

Давайте сразу настроим Swift Mailer /admin/config/swiftmailer/transport. На данной странице вам нужно выбрать как будет отправляться почта и данные для отправки. Аналогично модулю SMTP.

Настройки отправки почты Swift Mailer

Вверху переключившись на вкладку Messages, вы также можете настроить в каком формате будут уходить письма.

Настройки вкладки Messages

Настройка модуля Mail System

Модуль 1 в 1 как в Drupal 7 перекочевал и на Drupal 8. Всё что он делает, позволяет выбирать, какие интерфейсы будут использоваться для форматирования и отправки письма, с возможностью указывать тонкие настройки под конкретные модули и задачи. Разумеется нам по дефолту нужно выбрать Swift Mailer, так как он будет отсылать и формировать письма.

Настройки Mail System

Настройка модуля Contact

Для начала нам нужно включить поддержку html писем для Contact в настройках добавленные модулем Contact Storage (/admin/structure/contact/settings). Тут никаких сложностей не должно возникнуть.

А вот далее нам надо добавить формат вывода mail для сущности Contact Message. Он используется для формирования письма, если присутствует, конечно. Эта особенность захардкожена в самом модуле Contact (contact_mail()).

Для этого заходим в настройки View Modes (/admin/structure/display-modes/view) и для Contact message добавлем

Добавление нового формата отображения.

Теперь нужно перейти в настройки управления отображением для нужной контактной формы и включить формат вывода Mail.

Включение Mail для контактной формы.

После чего у вас сверху появится вкладка Mail и там вы сможете настроить то, как сообщение будет отправлено на почту, включая порядок и какие поля необходимо отправлять. Для формирования разметки вы также можете использовать здесь DisplaySuite + FieldGroup. Но и не забывайте что HTML писем достаточно большое количество ограничений, поэтому все же лучше взять контроль над результатом письма при помощи темплейт файла.

Следовательно, вы можете здесь настраивать как и что будет формировать тело письма. Вы можете использовать различные layouts и темплейты для того чтобы сформировать содержимое письма. Но что если вы хотите сделать общий каркас оформления отправляемых писем от модуля Contact? Тут нам и поможет Siwft Mailer. Он добавляет свой собственный шаблон swiftmailer.html.twig со следующим содержанием по умолчанию:

swiftmailer.html.twig
<html>
<head>
<style type="text/css">
table tr td {
  font-family: Arial;
  font-size: 12px;
}
</style>
</head>
<body>
<div>
  <table width="800px" cellpadding="0" cellspacing="0">
    <tr>
      <td>
        <div style="padding: 0px 0px 0px 0px;">
          {{ body }}
        </div>
      </td>
    </tr>
  </table>
</div>
</body>
</html>

Как вы могли понять, всё что вы настроите на вывод в управлении отображением Mail будет вставлено в body переменную данного темплейта.

Так вот, как же менять эту обертку под себя? Данный модуль регистрирует them hook suggestions для данного темплейт файла в следующем формате swiftmailer-MODULE-KEY.html.twig. Следовательно, вы можете объявить следующие темплейты:

  • swiftmailer.html.twig - будет использоваться для всех отправляемых писем с сайта через Swift Mailer класс, если не определен ни один из шаблонов ниже.
  • swiftmailer--contact.html.twig - будет использоваться для всех сообщений отправляемых модулем contact.
  • swiftmailer--contact--page-mail.html.twig - будет использоваться для сообщений, отправленных из формы получателям данной контактной формы.

У Contact также есть следующие ключи: - page-copy - копия письма отправляемая отправителю в случае если поставлена соответствующая галочка. - page-autoreply - письмо которое отправляется в качестве автоматического ответа отправителю после отправки его письма. - user-mail - письмо отправляемое через персональную контактную форму получателю (пользователю). - user-copy - копия письма отправителю, отправленное через персональную контактную форму.

Я решил что хочу переопределить вообще все исходящие contact письма и сделать им единый стиль оформления. Для этого в теме вашего сайта находится папа templates, в неё мы и помещаем нужный нам темплейт swiftmailer--contact.html.twig

swiftmailer--contact.html.twig
<html>
<head>
  <style type="text/css">
    table tr td {
      font-family: Arial;
      font-size: 14px;
    }
  </style>
</head>
<body style="background-color: #222222;">
<div style="width: 100%; padding: 20px 0; background-color: #222222;">
  <div style="max-width: 600px; margin: auto;">
    <table role="presentation" cellspacing="0" cellpadding="0" border="0"
           align="center" width="100%" style="max-width: 600px;">
      <tbody>
      <tr>
        <td>
          <img src="image:http://i.imgur.com/AZQIFhO.png" width="600" height="235"
               alt="alt_text" border="0" align="center"
               style="width: 100%; max-width: 600px;">
        </td>
      </tr>
      </tbody>
    </table>
    <table role="presentation" cellspacing="0" cellpadding="0" border="0"
           align="center" width="100%" style="max-width: 600px;">
      <tbody>
      <tr>
        <td style="background: white; padding: 30px">
          {{ body }}
        </td>
      </tr>
      </tbody>
    </table>
  </div>
</div>
</body>
</html>
Письмо по шаблону.

В целом это всё. Дальше лишь ваша фантазия и необходимость правки макета письма.

Обращу лишь внимание на ещё одну особенность. Изображение я вставил не просто так, посмотрите на путь до него: src="image:http://i.imgur.com/AZQIFhO.png" - приставка image перед адресом до изображения не просто так, она указывает Swift Mailer, что это изображение должно быть вставлено в письмо и отправлено вместе с ним через CID (Content-ID), при этом такой файл не отображается как прикрепленный. Это некий аналог data:base64.

С таким подходом, например, Gmail не запрашивает разрешение на подгрузку изображений из внешних источников, прежде чем отобразить их, а сразу показывает.

Комментарии

Михаил
08.10.2016

Грацио, Никита! Оч полезно.

Александр
19.04.2017

Отличная статья! А возможно ли вывести каждое поле отдельно? что-то вроде {{ body.field_name }} (так увы не работает)

Niklan
20.04.2017

Думаю можно. Ваш пример не работает потому что body поле самое по себе, а ваша структура пытается вызвать поле field_name у поля body? Это странно. Body же не сущность.

Я точно не могу сейчас сказать, надо препроцессить и смотреть, но опираясь на {{ body }} смею предположить что поле вызывается {{ field_name }}

Содержимое данного поля является приватным и не предназначено для показа.