Что нам стоит сервис email-маркетинга построить — взгляд изнутри
Кратко о себе
Я пишу на Python вот уже 5 лет, в основном использую Django, PostgreSQL, умею готовить JavaScript на уровне jQuery + KnockoutJS. В свободное от основной работы занимаюсь фрилансом и собственными интернет-проектами, об одном из которых сейчас и планирую рассказать. Занимаюсь я этим проектом уже около года.
Цель проекта
В самом начале мною была поставлена достаточно простая цель - создать работающее решение для отправки транзакционных писем и email-рассылок с функциями отслеживания открытий, переходов, невозможности доставки письма, жалоб на спам. Использовать я это решение планировал в других своих проектах, поскольку Яндекс ПДД (почта для домена), которую я использовал до этого, такими функциями не обладала, а они были нужны.
Тогда еще не шла речь о том, чтобы дать это решение в виде SaaS всем пользователям в Интернете.
Задачи
- Понять, как работает отслеживание событий в email-рассылках, разобраться с трекингом
- Придумать решение, которое будет работать под средними нагрузками (2-3 миллиона писем в месяц). Почему именно 2-3 миллиона? Я считаю, что такой объем необходим, чтобы окупать такой проект (затрачиваемое время + материальные ресурсы типа серверов)
- Реализовать удобный интерфейс для аналитики массовых и транзакционных рассылок
Далее я постараюсь более-менее подробно остановиться на том, как я выполнил каждую из этих задач.
Технологии
Использовать я решил те технологии, которые знаю - Python, Django, PostgreSQL, KnockoutJS, LESS, py.test.
Дополнительно в процессе работы над проектом я неплохо разобрался в Celery и микросервисной архитектуре.
На этом я предлагаю закончить вступительную часть и перейти к самому интересному - практике.
Как работает трекинг email-сообщений?
Когда вы отправляете почту, вы наверняка хотите знать, дошли ли ваши письма адресатам, прочитали ли они их вообще, интересны ли они им, перешли ли они по ссылкам в письме, что после этого они делали на сайте, совершили ли целевое действие - покупку, заказ, звонок и так далее.
Получить ответы на эти вопросы вы можете только с помощью трекинга или систем типа Яндекс.Метрики (ну или спросив своих получателей лично).
Отслеживание открытий писем
Сегодня стандартным подходом для отслеживания открытий писем является внедрение специального пикселя в письмо - вы можете увидеть этот пиксель в большей части рекламных писем в вашем почтовом ящике, если посмотрите исходники письма. Он может выглядеть примерно так:
<img src="http://api.mailhandler.ru/message/track/<UNIQUE_EMAIL_ID>/OPENED/" width="1px" height="1px" border="0"/>
Понятно, что при запросе на URL, указанный в атрибуте src изображения, должно происходить добавление события, означающего, что письмо с id равным UNIQUE_EMAIL_ID было открыто.
Однако не всё так просто. Очень часто в src изображения указывают URL, ведущий на какой-либо php-скрипт и не думают о том, что почтовый клиент очень хочет получить в ответ валидные для изображения заголовки, а так же само изображение. Если почтовый клиент по этой причине разочаровывается в вашем пикселе, он просто вырежет его из письма и вы не узнаете о том, открыл ваш адресат письмо или нет.
Для того, чтобы этого не произошло, следует добавить корректные заголовки ответа и отдать валидное изображение клиенту. Реализация на Django Rest Framework может выглядеть примерно так - https://gist.github.com/astrikov-d/9f3eccbdf1ca54b...
Отслеживание переходов по ссылкам в письме
Думаю, у пытливого читателя не должно возникнуть проблем с реализацией такого типа трекинга. В общем и целом - каждая ссылка в письме заменяется на ссылку через специальный сервис перенаправления, который создает событие типа "Переход по ссылке". Дополнительно можно к каждой ссылке добавлять уникальный идентификатор - тогда вы сможете реализовать "тепловую карту" письма. Это очень полезная функция, например, для А/Б тестирования.
Отслеживание невозможности доставки писем
А вот с этим все намного интереснее.
Каждый раз, когда почтовый сервер не может доставить ваше письмо, в ответ на адрес отправителя уходит отчет о невозможности доставки с описанием причины (иногда подробным, иногда - так себе). Для обработки этих входящих писем я использовал подход, который заключается в пробросе входящего письма на Python скрипт обработчика через /etc/aliases.
Сам скрипт пытается более-менее интеллектуально пытается понять причину невозможности доставки письма и создает событие Soft-Bounce (письмо в данный момент не может быть доставлено, но вы сможете попробовать еще разок) или Hard-Bounce (письмо не будет доставлено никогда, например потому что ящик не существует).
Тут важно сделать небольшую ремарку о том, как собственно нужно реагировать на такие события согласно правилам почтовых сервисов типа Mail.ru, Yandex и др.
сервисы, осуществляющие рассылки на основе подписки, должны безусловно удалять из базы подписчиков или принимать меры по приостановке рассылок на адреса, которые генерируют ошибку протокола SMTP: 550 user not found (отслеживание валидности базы получателей — необходимое условие для поддержания положительной репутации рассыльщика);
Ссылка на список правил: https://help.mail.ru/mail-help/rules/technical
Таким образом, мне необходимо было предусмотреть "выключение" подписчиков, на адреса которых невозможно доставить почту. В итоге я пришел к тому, что выключаю подписчика из всех списков подписчиков на сервисе.
Ну вот, с трекингом вроде бы разобрались.
Немного статистики
В данный момент через мой сервис отправляется около 150 000 писем в месяц. Много это, или мало? Наверное мало, учитывая объемы, которые я себе задал в рамках обозначенных задач.
Из них:
- 20% - открыты (это достаточно большой процент, на самом деле, спасибо транзакционной почте)
- 13% - переходы по ссылкам
- 9% - Hard/Soft bounce
P.S.
В следующих статьях я расскажу о том, как и чем я обрабатываю эти данные, расскажу о тонкостях использования celery в подобных проектах, а так же остановлюсь на том, что я планирую делать с этим сервисом дальше.
Спасибо за внимание!