Зробили email-розсилку для інтернет-магазину. Верстка на таблицях, тестували в Gmail — все ок. Але в Outlook 2016 лист розвалився: кнопка з'їхала, шрифти пропали, а картинка не завантажилась. Знайома ситуація — її виправляє MJML.
Проблема в тому, що Outlook використовує Word для рендерингу HTML, а не Edge або WebKit. MJML вирішує цю біль: ви пишете компоненти на декларативній мові, а на виході отримуєте валідний табличний HTML, перевірений у 90+ поштових клієнтах. Ми використовуємо MJML у зв'язці з Handlebars та Node.js, щоб шаблони були не лише красивими, але й легко інтегрувалися з будь-яким бекендом.
Чому MJML рятує від Outlook-головного болю?
- Outlook-сумісність. За статистикою Litmus, близько 9% користувачів відкривають листи в Outlook. Якщо ваш шаблон не адаптований під Word HTML, лист може відобразитися некоректно: роз'їдуться колонки, пропадуть background-image, не спрацюють border-radius. MJML генерує табличну верстку з VML-кодом, яка коректно рендериться в Outlook. Ми додатково тестуємо кожен шаблон на 5 версіях Outlook через Litmus.
- Адаптивність для мобільних. Понад 50% листів відкривають на телефонах. MJML сам створює медіа-запити та fluid-таблиці, щоб лист виглядав однаково добре на iPhone 15, Samsung Galaxy та десктопі.
- Швидкість розробки. Типовий шаблон на таблицях вручну — 3-4 години. На MJML — 30–40 хвилин. Плюс знижується ймовірність помилок: не потрібно пам'ятати quirks-режими кожного клієнта.
Як ми це робимо?
Розберемо реальний кейс — інтернет-магазин електроніки. Клієнт хотів 4 трансакційні листи: підтвердження замовлення, сповіщення про відвантаження, скидання пароля та вітання.
Стек: MJML 4.15, Handlebars 2.0, Node.js 20 з TypeScript, компілятор mjml CLI, тестування в Litmus.
Ми почали зі створення загальної бази — mj-attributes для шрифтів, кольорів та кнопок. Це забезпечило єдиний стиль у всіх листах. Потім для кожного листа написали MJML-компонент, розбивши інтерфейс на секції: header, content, cta, footer. У місця вставки динамічних даних (ім'я, номер замовлення, товари) додали Handlebars-змінні.
Приклад — лист підтвердження замовлення з таблицею товарів. Використали <mj-table> для рядків, щоб вони коректно відображалися в Outlook. Кнопку "Відстежувати замовлення" зробили через <mj-button> — він генерує VML для Outlook.
Після компіляції отримали HTML-файли розміром ~15 КБ кожен. Інтеграція з бекендом — через Node.js-функцію, яка приймає JSON з даними замовлення, підставляє їх через Handlebars і повертає готовий HTML для відправки.
Процес роботи
- Аналітика — визначаємо типи листів, узгоджуємо макети та тексти.
- Проектування — створюємо прототипи в MJML, показуємо клієнту в тестовому середовищі.
- Реалізація — верстаємо шаблони, додаємо Handlebars-змінні.
- Тестування — прогоняємо через Litmus, фіксимо баги в Outlook та мобільних клієнтах.
- Деплой — передаємо HTML-файли або код рендерингу на Node.js, пишемо документацію з інтеграції.
Терміни орієнтовно
Набір з 3-5 трансакційних шаблонів (order, reset password, welcome) — 4-6 робочих днів. Складні шаблони з кастомною анімацією або AMP для email — до 8 днів.
Що входить в роботу
- Вихідники MJML (компоненти)
- Скомпільовані HTML-файли
- Handlebars-шаблони для вашого бекенду
- Інструкція з інтеграції з SendGrid, Amazon SES або будь-яким SMTP
- Звіт тестування в Litmus зі скріншотами
- Гарантія коректного відображення в Outlook, Gmail, Apple Mail
- Підтримка протягом 14 днів після здачі
Чому MJML краще табличної верстки?
| Критерій |
Таблична верстка вручну |
MJML |
| Час на шаблон |
3-4 години |
30-40 хвилин |
| Підтримка Outlook |
Потрібне ручне правлення VML |
Автоматична генерація |
| Адаптивність |
Потрібні медіа-запити руками |
Вбудовані fluid-колонки |
| Помилки |
Висока ймовірність |
Мінімальна (валідація на етапі компіляції) |
Як тестувати шаблони у всіх поштових клієнтах?
Використовуємо сервіси Litmus або Email on Acid — вони роблять скріншоти в реальних клієнтах. Для швидкої перевірки локально — плагін MJML Preview для VS Code або команда mjml -w для авто-перескладання. Для функціонального тестування — відправка в тестовий inbox через Mailtrap.
Тестовані клієнти
| Клієнт |
Версія |
| Outlook |
2013, 2016, 2019, 2021 |
| Gmail |
Web, iOS, Android |
| Apple Mail |
iOS, macOS |
| Yahoo Mail |
Web, iOS, Android |
| Outlook.com |
Web, iOS, Android |
Зв'яжіться з нами для оцінки вашого проєкту. Ми підготуємо пропозицію за 1 день — з підбором стеку та термінами. Замовте розробку під ключ і отримайте адаптивні шаблони, які гарантовано працюють в Outlook. Отримайте консультацію по ваших шаблонах — це безкоштовно.
Інтеграція email розсилок: чому вона часто ламається?
Ми стикалися з тим, що тригерний лист через 10 хвилин після реєстрації конвертує в 4–5 разів краще, ніж той самий лист через 24 години. Це не маркетинговий міф — це механіка: поки користувач теплий, поки пам'ятає контекст. Але більшість інтеграцій з розсильниками зроблені так: форма сабмітиться → синхронний HTTP-запит до API → якщо API гальмує, користувач чекає 3 секунди → лист йде або не йде, ніхто не знає.
Якщо ви зіткнулися з втраченими листами або потраплянням у спам, замовте аудит існуючої інтеграції — ми знайдемо вузькі місця за 2 дні.
Провайдери та їх API
Unisender — російський провайдер, популярний у сегменті SMB. REST API, простий. Додавання контакту: importContacts, відправка транзакційного листа: sendEmail. Важливо: для транзакційних листів (підтвердження замовлення, скидання пароля) Unisender Go — окремий сервіс з іншим API та окремою ціною. Змішувати масові розсилки та транзакційні в одному потоці — погана ідея для репутації домену.
SendPulse — надає email, SMS, web push, Viber, Telegram-боти через єдиний API. Для проєктів, де потрібен омніканал, це зручно. Automation 360 — візуальний конструктор ланцюжків, можна запустити автоматизацію через API event. SDK для PHP (sendpulse/rest-api-php-sdk) підтримується, але оновлюється нерегулярно — краще використовувати напряму через Guzzle.
Mailchimp — вибір для міжнародної аудиторії та маркетингових команд, звиклих до екосистеми Mailchimp. Transactional email — через Mandrill (дочірній сервіс). Marketing API v3 для управління списками, тегами, кампаніями. Webhook для подій: відкриття, клік, відписка, bounce.
SMS. Для Росії: СМСЦ, МТС Exolve, Devino Telecom, SMS Aero. API у всіх схожий: метод send, параметри phone, message, sender (ім'я відправника — потрібно реєструвати окремо у оператора). Один нюанс: ім'я відправника має бути зареєстровано через агрегатора з договором — без цього SMS не відправляться на мережі МТС/МегаФон/Білайн.
| Провайдер |
Тип |
Транзакційні листи |
Маркетингові |
Особливості |
| Unisender |
email+SMS |
Unisender Go (окремо) |
так |
Популярний в РФ, простий REST |
| SendPulse |
email+SMS+web push+Viber |
так |
так |
Єдиний API, омніканальність |
| Mailchimp |
email |
Mandrill |
так |
Аналітика, міжнародний |
| Twilio |
SMS+email |
так |
ні |
Глобальний, дорогий в РФ |
Як побудувати інтеграцію, щоб не втрачати листи?
Розділяємо транзакційні та маркетингові потоки
Транзакційні листи (підтвердження замовлення, скидання пароля, статус доставки) — через окремий домен-відправник або субдомен tx.example.com. Маркетингові розсилки — через mail.example.com або news.example.com. Якщо маркетингова розсилка отримає багато скарг на спам, це не повинно зачепити репутацію транзакційного потоку. Згідно з документацією SendGrid, транзакційні повідомлення слід відправляти через виділений IP-пул для запобігання перехресному впливу.
Черга та retry
Будь-який виклик до email API — через чергу (Laravel Queue, Bull, Celery). Якщо Unisender повернув 503 — задача йде в retry через 5 хвилин, потім 15, потім 60. Після 5 невдалих спроб — у dead letter queue з алертом. Користувач при цьому вже отримав свій 200 OK і не знає про проблему. Завдяки цьому підходу bounce rate на проєктах знижується до 0.5%.
Приклад job для Laravel:
public function handle(): void
{
try {
$response = Http::post(config('services.unisender.email_url'), $this->params);
if ($response->failed()) {
$this->release(300); // retry через 5 хв
}
} catch (\Throwable $e) {
$this->release(300);
}
}
Шаблони
Зберігаємо шаблони в коді (Blade, Twig, React Email), не в інтерфейсі провайдера. Причини: версіонування через Git, preview у браузері без відправки, можливість тестування. Для складних шаблонів з динамічним контентом — react-email з експортом в HTML через @react-email/render.
Валідація та згоди
Перед додаванням контакту до списку — double opt-in (лист з підтвердженням). Зберігати факт підтвердження з timestamp у своїй БД. При відписці — синхронно відписуємо і у провайдера, і в своїй базі. Ігнорувати webhook відписки — прямий шлях до блокування акаунта у провайдера. Всі процеси відповідають ФЗ-152 про персональні дані.
Як налаштувати DKIM для домену-відправника?
DKIM дозволяє підписувати листи цифровим підписом, що підвищує довіру поштових серверів.
- Згенеруйте пару ключів (наприклад, через OpenSSL:
openssl genrsa -out private.key 2048).
- Опублікуйте публічний ключ у DNS як TXT-запис для селектора (наприклад,
mail._domainkey.tx.example.com).
- Вкажіть селектор у провайдера (SendGrid, Mailgun, Unisender).
- Перевірте командою
dig TXT mail._domainkey.tx.example.com.
Моніторинг доставності
Підключаємо webhook від провайдера на події bounce (жорсткий і м'який), spam_complaint, unsubscribe. Жорсткий bounce — негайно позначаємо email як невалідний у своїй БД, більше не відправляємо. М'який bounce 3 рази поспіль — те саме. Метрики: open rate, click rate, bounce rate, unsubscribe rate — дивимося не рідше разу на тиждень. Наші сертифіковані інженери налаштовують алерти в Grafana/Prometheus.
Чому важливо розділяти потоки?
Якщо відправити маркетингову розсилку з того ж домену, що й транзакційні листи, отримавши скарги на спам, ви ризикуєте заблокувати домен — і користувачі перестануть отримувати навіть підтвердження замовлень. SPF, DKIM, DMARC (Wikipedia SPF, Wikipedia DKIM) повинні бути налаштовані окремо для кожного потоку. Ми використовуємо субдомени з різними DNS-записами.
Обсяг робіт з інтеграції
- Аудит поточних потоків комунікації та репутації домену (SPF, DKIM, DMARC)
- Вибір провайдера та схеми: транзакційний vs маркетинговий трафік
- Налаштування DNS-записів SPF, DKIM, DMARC (Wikipedia DMARC)
- Розробка шаблонів листів (HTML + динамічний контент)
- Інтеграція з бекендом через черги та API
- Налаштування webhook для доставності та скарг
- Документація з експлуатації та навчання команди
- Гарантія доставності та підтримка після запуску
Терміни та вартість
| Сценарій |
Термін (робочі дні) |
Примітка |
| Базові транзакційні листи (один провайдер) |
5–7 днів |
Ціна розраховується індивідуально після аудиту |
| Тригерні ланцюжки + SMS + веб-пуши |
10–20 днів |
Ціна розраховується індивідуально після аудиту |
| Повна омніканальна автоматизація |
20–40 днів |
Ціна розраховується індивідуально після аудиту |
Вартість розраховується індивідуально після аудиту. Ми працюємо під ключ: від аналізу до моніторингу в продакшені. Отримайте консультацію інженера — оцінимо проєкт безкоштовно та скажемо точні терміни. Досвід більше 7 років в інтеграції поштових сервісів, реалізовано 50+ проєктів. Замовте безкоштовний аудит поточної інтеграції — отримайте звіт з рекомендаціями.