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

В этой статье я расскажу о том, как улучшить стандартный модуль для контактных форм Contact. Это позволит без применения кода, немного управлять поведением Contact, добавить возможность сохранения отправленных писем, а также позволит отправлять письма в формате HTML.

04.09.2016
9 комментариев
8 мин.

Изначально я хотел просто разобраться с модулем 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 не запрашивает разрешение на подгрузку изображений из внешних источников, прежде чем отобразить их, а сразу показывает.

Drupal
Drupal 8
Contact

Комментарии

Александр   ср, 19/04/2017 - 12:29

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

Niklan   чт, 20/04/2017 - 09:55

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

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

Александр   пт, 21/07/2017 - 17:25

Здравствуйте, я отправляю письма с помощью hook_mail, а не swiftmailer. Подскажите как мне написать темплейт для этих писем? Знаю, что нужно использовать hook_theme, но что в нем писать, и что делать после этого не знаю.

Гермиона Грейнджер   вт, 20/06/2023 - 16:40

Спасибо за статью. Вовремя узнала про Contact Storage, а то уже хотела качать WebForm ради необходимости сохранять письма в базе.
А не подскажете, что именно нужно добавить в hook_mail_alter чтобы письма уходили в html формте? Замены заголовка на 'text/html; charset=UTF-8\r\n' не достаточно.
Имеется в виду, если не использовать swift mailer и пр., а ограничиться только лишь модулями Contact и Contact Storage.

Гермиона Грейнджер   ср, 21/06/2023 - 09:21

Не сомневаюсь, что Symfony Mailer прекрасный модуль. Но если всё, что нужно сделать в письме - это выделить жирным пару строк, то кажется лишним ставить дополнительный модуль. Поэтому и хочется добиться html формата с тем, что есть. Но что-то не получается.

Niklan   ср, 21/06/2023 - 10:09

Не знаю как без него сделать правильно. Лучше гуглить как правильно сформировать HTML письмо вообще без Drupal. Не думаю что одного лишь заголовка хватит. Ведь для HTML письма нужно ещё должным образом сформировать тело письма, там же не сырой HTML отправляется, его тоже нужно готовить.

Symfony Mailer также возьмёт на себя все заботы о корректном аттачменте файлов письма и его темизации (если нужно).

Имхо, его лучше поставить, он закрывает множество вопросов, включая транспорты, через которые отсылать эти самые письма. Ведь, например, даже для отправки через SMTP, в Drupal из коробки придётся хорошенько попариться или ставить контриб. Symfony Mailer и это решает без дополнительных модулей.

Плюс он переводит работу с письмами в Drupal на плагины и вообще, там цель чтобы этот модуль стал частью ядра. Так что он того стоит, решает множество проблем, и при этом, делает с десяток прочих модулей - ненужными.

Также, Contact Message только хранит сообщения, отправкой занимается ядро и подлезать там не очень приятно. Для этого есть Contact Emails, но опять, его функционал полностью заменяется Symfony Mailer в едином формате для вообще всей почты с сайта.

Гермиона Грейнджер   ср, 21/06/2023 - 10:35

Очень убедительно. Спасибо. Будем пробовать Symfony Mailer