Статьи

Отправка электронной почты с использованием Node.js

Большинству веб-приложений нужно будет отправлять нечетные электронные письма. Будь то транзакционный характер или ориентированный на маркетинг — например, информационные бюллетени, рекламные акции или рекомендации по продуктам — это довольно повсеместное требование. И если вы отправляете электронную почту, скорее всего, вы захотите отправить их с помощью HTML.

На самом деле отправка писем довольно проста. Тем не менее, при отправке на уровне громкости необходимо учитывать множество дополнительных проблем, таких как обработка отскоков, отслеживание кликов и борьба с фильтрами спама.

Однако для целей этой статьи нас больше интересует, как обрабатывать ваши HTML-шаблоны электронной почты вместе со всеми возникающими проблемами.

К сожалению, различные ограничения, причуды и различия между почтовыми клиентами означают, что электронные письма HTML сопряжены с трудностями.

Тем не менее, существует множество хороших ресурсов по созданию электронных писем в формате HTML, даже только через SitePoint. Есть руководство Массимо по созданию вашей первой электронной рассылки , руководство Тима по их кодированию и серия Лорен о лучших практиках .

Тем не менее, в центре внимания этой статьи не столько проблемы, с которыми вы сталкиваетесь при разработке электронных писем в формате HTML, а некоторые инструменты, которые могут помочь автоматизировать этот процесс за вас. Мы сосредоточимся на двух основных областях: отправка электронных писем в формате HTML из приложения Node.js и использование таких инструментов, как Grunt.

Давайте посмотрим на пару основных вопросов и некоторые решения.

Версии простого текста

Хотя возможности рендеринга HTML в почтовых клиентах, как правило, далеко от того, что вы можете делать в браузере, большинство из них поддерживают HTML — элементарный, как они могут быть. Но не все. Кроме того, некоторые люди явно предпочитают получать версии в виде простого текста и блокируют версии HTML в своем клиенте. Поэтому нам необходимо отправить текстовую версию, а также ваше поющее и танцующее электронное письмо в формате HTML.

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

Существует плагин Nodemailer (который мы вскоре рассмотрим) для автоматического извлечения текста из электронного письма в формате HTML, и это одна из задач, выполняемых Premailer — еще одним инструментом, который мы рассмотрим позже.

Встраивание CSS

Из-за ограничений многих почтовых клиентов вы всегда должны встроить свой CSS .

Мы не просто говорим о добавлении ваших стилей в <style><head> Скорее стили CSS должны применяться к каждому элементу с помощью встроенного атрибута style Рассмотрим следующий пример:

 .btn-primary {
  text-decoration: none;
  color: #FFF;
  background-color: #348eda;
  border: solid #348eda;
  border-width: 10px 20px;
  line-height: 2;
  font-weight: bold;
  text-align: center;
  cursor: pointer;
  display: inline-block;
  border-radius: 5px;
  text-transform: capitalize;
}
 <tr>
  <td class="content-block">
    We may need to send you critical information about our service and it is important that we have an accurate email address.
  </td>
</tr>
<tr>
  <td class="content-block">
    <a href="{{ url }}" class="btn-primary">Confirm your email address</a>
  </td>
</tr>

Вот тот же фрагмент HTML с CSS-кодом:

 <tr style="margin: 0; padding: 0; font-family: Helvetica Neue, Helvetica, Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">
  <td class="content-block" style="margin: 0; padding: 0 0 20px; font-family: Helvetica Neue, Helvetica, Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top;">
    We may need to send you critical information about our service and it is important that we have an accurate email address.
  </td>
</tr>
<tr style="margin: 0; padding: 0; font-family: Helvetica Neue, Helvetica, Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px;">
  <td class="content-block" style="margin: 0; padding: 0 0 20px; font-family: Helvetica Neue, Helvetica, Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top;">
    <a href="{{ url }}" class="btn-primary" style="margin: 0; padding: 0; font-family: Helvetica Neue, Helvetica, Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; color: #FFF; text-decoration: none; background-color: #348eda; border: solid #348eda; border-width: 10px 20px; line-height: 2; font-weight: bold; text-align: center; cursor: pointer; display: inline-block; border-radius: 5px; text-transform: capitalize;">Confirm your email address</a>
  </td>
</tr>

Откровенно говоря, сделать это вручную было бы огромной рутиной, не говоря уже о том, чтобы сделать ваши HTML-шаблоны электронной почты практически не поддерживаемыми. Это также та задача, которая требует автоматизации. Конечно, есть ряд решений, которые мы рассмотрим сейчас.

Сок

Juice — это библиотека JavaScript для автоматической вставки вашего CSS, что делает его идеальным для электронных писем в формате HTML. Просто предоставьте ему некоторый HTML-код и таблицу стилей, и он превратит его для вас в неуправляемый беспорядок, как в примере выше.

Вы можете использовать Juice в приложениях Node.js, используя модуль , с Grunt или с Gulp .

Grunt Inline CSS

Вы также можете использовать этот плагин Grunt . Использование простое.

Установите плагин:

 npm install grunt-inline-css --save-dev

Зарегистрировать задачу:

 grunt.loadNpmTasks('grunt-inline-css');

Наконец, настройте его, чтобы сказать, что обрабатывать:

 grunt.initConfig({
  inlinecss: {
    main: {
      options: {
      },
      files: {
        'templates/emails/_inlined/confirm-email.html': 'templates/emails/_raw/confirm-email.html',
        'templates/emails/_inlined/password-reset.html': 'templates/emails/_raw/password-reset.html'
      }
    }
  }
})

Стоит отметить, что за кулисами плагин использует Juice.

Premailer

Premailer — это онлайн-сервис для обработки электронных писем в формате HTML, который выполняет ряд задач:

  • Подчеркивает ваш CSS
  • Преобразует относительные пути, такие как ссылки, в абсолютные пути
  • Проверяет свойства CSS на предмет возможностей почтового клиента
  • По желанию, он может автоматически создать альтернативную текстовую версию для вас

Использование веб-службы для этого очень хорошо, но необходимость вручную копировать и вставлять исходный код каждый раз, когда вы вносите изменения, может быть довольно быстро утомительной. К счастью, есть также API , а еще лучше — пакет, который делает использование API из приложения Node еще проще.

Чтобы установить пакет, выполните следующее:

 npm install premailer-api

Вот простой пример инструмента командной строки, который берет необработанный шаблон, хранящийся в виде файла с именем in.html Затем он выводит обработанный HTML в out.htmlout.txt

 var premailer = require('premailer-api')
  , fs = require('fs');

var template = fs.readFileSync('./in.html', 'utf8');

premailer.prepare(
  {
    html: template 
  }, 
  function(err, email) {  
    fs.writeFileSync('out.html', email.html);
    fs.writeFileSync('out.txt', email.text);
  }
);

Для иллюстрации — приведен следующий HTML:

 <!-- in.html -->
<html>
  <head>
    <title>My Email</title>
    <style type="text/css">
      a { color: #336699; }
    </style>
  </head>
  <body>
    Styles inlined with 
    <a href="http://premailer.dialect.ca">Premailer</a> via 
    <a href="https://github.com/JedWatson/node-premailer">node-premailer</a>.
  </body>
<html>

Это даст вам следующее:

 <!-- out.html -->
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
  <title>My Email</title>
  <style type="text/css">
    a { color: #336699; }
  </style>
</head>
<body>
  Styles inlined with 
  <a href="http://premailer.dialect.ca" style="color: #336699;">Premailer</a> via 
  <a href="https://github.com/JedWatson/node-premailer" style="color: #336699;">node-premailer</a>.
</body>
</html>

И текстовая версия:

 // out.txt
Styles inlined with
Premailer ( http://premailer.dialect.ca ) via
node-premailer ( https://github.com/JedWatson/node-premailer ).

Обратите внимание, что в дополнение к встраиванию CSS, Premailer также конвертировал ссылки в соответствии с простым текстом.

Существует ряд опций, которые вы можете использовать — для получения более подробной информации обратитесь к документации Premailer .

Есть несколько способов использовать Premailer. Есть плагин Grunt, плагин Gulp , или вы можете прокрутить свой собственный инструмент командной строки в соответствии с приведенным выше примером кода.

Прочие активы

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

Есть несколько вещей, которые вы можете сделать со своими изображениями. Очевидно, что связанные изображения должны быть доступны извне, поэтому важно убедиться, что вы используете абсолютные, а не относительные пути. Premailer является одним из вариантов здесь.

Обычный подход заключается в загрузке изображений для электронной почты в формате HTML в сеть доставки контента (CDN) или службу, такую ​​как Amazon S3.

Пакет Grunt Email Design Workflow интегрируется с облачными файлами Rackspace или существует несколько плагинов для интеграции с S3 .

Задачи бегунов

Мы затронули несколько инструментов, которые можно использовать у таких исполнителей, как Grunt или Gulp.

Пример рабочего процесса Grunt / Gulp может включать:

  • Встраивание CSS с помощью Juice
  • Идентификация изображений, загрузка на S3 и исправление их путей
  • Сокращение HTML
  • Предварительная компиляция шаблонов Handlebars
  • Объединение предварительно скомпилированных шаблонов в файл JST

Возможно, самый простой способ использовать Grunt для обработки ваших шаблонов электронной почты — это начать с Grunt Email Boilerplate . Там есть много функциональных возможностей — не все, которые вы обязательно захотите использовать — поэтому изучите документацию, чтобы посмотреть, что она может сделать. И, естественно, есть что-то похожее для Gulp .

Если Yeoman — ваша вещь, есть ряд генераторов, доступных специально для электронных писем HTML, таких как этот .

Библиотека шаблонов электронной почты

Что касается решений Node.js, вы можете назвать библиотеку шаблонов электронной почты швейцарским ножом HTML-писем.

Он берет на себя почти весь процесс создания электронных писем в формате HTML и многое другое.

Библиотека предоставляет следующие возможности:

  • Поддержка ejs, Jade, Swig, Handlebars, Emblem and Dust
  • Предварительная обработка CSS с использованием Less, SASS, Stylus или Styl
  • CSS inlinig, используя Juice
  • Интеграция с Nodemailer, Postmark
  • Поддержка пакетной отправки

Другими словами, это раковина HTML-писем для Node. Давайте посмотрим на это, и как это использовать.

использование

Установить через npm:

 npm install email-templates

Затем создайте каталог где-нибудь для хранения ваших шаблонов. В рамках этого создайте каталог для каждого типа электронной почты. Например, один каталог для писем с подтверждением, другой для инструкций по сбросу пароля и, возможно, универсальная оболочка для сообщений.

Вот пример структуры каталогов:

 templates
  emails
    confirm-email
    password-reset
    welcome

Далее создайте свои шаблоны. Как минимум, каждому из ваших почтовых производных нужен шаблон для рендеринга HTML-версии. Его имя файла важно — оно должно называться html.ext.ext Так, например, если вы используете Handlebars, вы захотите назвать свой файл html.hbshtml.jade Обратите внимание, что вам нужно убедиться, что установлен соответствующий шаблонизатор!

Скорее всего, вы также захотите создать таблицу стилей. Вызовите этот styles.ext .css.scss.less

Если вы предпочитаете создавать свою собственную текстовую версию, создайте файл с именем text.ext С расширением действуют те же правила, что и с шаблоном HTML, поэтому оно будет называться как text.hbstext.jade

Чтобы проиллюстрировать это, вот как вы можете расположить каталог confirm-email

 templates
  emails
    confirm-email
      html.hbs
      text.hbs
      styles.scss

Далее вам нужно настроить свой транспортный механизм. Библиотека работает без проблем с NodeMailer и Postmark ; для целей этой статьи мы будем использовать Nodemailer, поскольку он не требует никаких сторонних сервисов и является одним из самых популярных вариантов отправки электронной почты с Node.ks.

В большинстве случаев вам, вероятно, захочется использовать Nodemailer через SMTP, хотя есть и другие виды транспорта , от Sendmail до SES и Sendgrid .

Вот пример использования SMTP:

 var nodemailer = require('nodemailer');
var transport = nodemailer.createTransport(smtpTransport({
  host: 'smtp.yourprovider.org',
  port: 25,
  auth: {
    user: 'username',
    pass: 'password'
  }
}));

Если вы используете Gmail, который использует некоторые нестандартные настройки, вы можете использовать следующий ярлык:

 var nodemailer = require('nodemailer');
var transport = nodemailer.createTransport({
  service: 'gmail',
  auth: {
    user: '[email protected]',
    pass: 'password'
  }
});

Теперь, когда он настроен, вы можете отправить одно электронное письмо следующим образом:

 emailTemplates(templatesDir, function(err, template) {

  if (err) {
    console.log(err);
  } else {

  var locals = {
    email: '[email protected]',
    url: 'http://acme.com/confirm/xxx-yyy-zzz'
  };

    // Send a single email
    template('confirm-email', locals, function(err, html, text) {
      if (err) {
        console.log(err);
      } else {
        transport.sendMail({
          from: 'Acme Corp <[email protected]>',
          to: locals.email,
          subject: 'Please confirm your e-mail address',
          html: html,
          text: text
        }, function(err, responseStatus) {
          if (err) {
            console.log(err);
          } else {
            console.log(responseStatus.message);
          }
        });
      }
    });
  }
});

За и против из библиотеки шаблонов электронной почты

Очевидно, что библиотека решает множество проблем, связанных с HTML-письмами. Это также дает вам большую степень гибкости. Если вы хотите использовать Jade и SASS, вы можете — также Handlebars and Less или Swig and Stylus.

Однако одно: если у вас большой объем отправляемых электронных писем, вы можете отправлять их партиями, и библиотека будет обрабатывать ваши шаблоны только один раз за пакет. Однако в следующий раз, когда вы отправите электронное письмо или пакет электронных писем, он снова пройдет весь процесс. Если вы отправляете ОЧЕНЬ много писем, вам лучше создать предварительно скомпилированные шаблоны.

Помните также, что вам нужно позаботиться о том, чтобы ссылки и пути к ресурсам были абсолютными, а также при необходимости оптимизировать свои изображения или загружать ресурсы в сеть доставки контента (CDN).

Тестирование ваших электронных писем в формате HTML

Конечно, ни одно руководство по отправке электронных писем в формате HTML не будет полным без примечания о тестировании.

Mailcatcher — действительно полезный инструмент для «перехвата» электронных писем, отправленных из вашего приложения. Вы просто запускаете его как фоновый процесс на своем компьютере, настраиваете приложение для использования соответствующего порта и можете просматривать электронные письма через веб-интерфейс на своем компьютере. Мэтью Сеттер написал подробное введение в нее здесь, на SitePoint .

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

Вывод

Письма в формате HTML могут быть настоящей болью, но многие головные боли могут быть смягчены с помощью автоматизации. В этой статье я рассмотрел несколько вариантов, как из приложений Node.js, так и с помощью запуска задач, таких как Grunt. Надеюсь, я дал вам достаточно ресурсов, чтобы вы начали. Посмотрите вокруг и посмотрите, что подходит вам, вашему рабочему процессу и вашему приложению лучше всего. Если вы знаете какие-либо другие полезные инструменты, которые я не рассмотрел, дайте мне знать в комментариях.