Для взаимодействия сервиса Mandrill с приложением, существует API с довольно широким спектром возможностей, с основными из них нам и предстоит, познакомиться. К тому же имеется возможность использования базового (бесплатного аккаунта) позволяющего производить рассылку до 12000 писем в месяц.
Использование API
Поскольку осуществление взаимодействия с API Mandrill предполагается реализовывать на PHP, то саму библиотеку берем отсюда. Можно воспользоваться установкой через Composer или стандартной установкой (скачиваем, распаковываем и подключаем необходимые модули). Если вы выбрали второй вариант установки, то вам необходимо найти в скачанном архиве каталог “src”, в нем то и содержатся файлы и каталоги необходимой библиотеки.
Для того чтобы иметь возможность использования API, необходимо получить API ключ (имеется ввиду, что вы уже зарегистрированы). Заходим в аккаунт и слева в меню кликаем по пункту “Settings” и в разделе “API Keys” сможем увидеть свой ключ:
Далее потребуется создать субаккаунт. Для этого опять же в левостороннем меню кликаем по пункту “Outbound” и после открытия соответствующего раздела настроек, нажимаем кнопку “Create a Subaccount”:
Для отправки письма можно воспользоваться заранее созданным шаблоном, который должен быть доступен в вашем аккаунте, или же ограничиться отправкой обычного текстового сообщения. Также имеется возможность оформления письма в формате HTML. Для отправки письма, существуют следующие методы класса Mandrill_Messages:
- array send(message [, async = false [, ip_pool = null [, send_at = null]]]) – в качестве параметра message требуется передать заполненную в виде массива структуру данных, приводимую в табл. 1. Параметр async – устанавливает фоновую пакетную отправку сообщений. В качестве параметра ip_pool требуется указывать имя выделенного пула ip адресов, как видно из описания прототипа функции этот параметр не является обязательным. И в качестве последнего параметра send_at можно указать время в формате UTC timestamp YYYY-MM-DD HH:MM:SS для запланированной отправки письма. Но для этого потребуется платный аккаунт с положительным балансом;
- array sendTemplate(template_name, template_content, message [, async = false [, ip_pool = null [, send_at = null]]]) – данный метод отличается от предыдущего наличием двух дополнительных параметров. В первом параметре template_name указывается имя существующего шаблона. А второй параметр template_content является массивом элементов динамического контента, структура данных которых описана в табл. 2. Подробнее можно ознакомиться здесь.
Таблица 1. Описание полей структуры данных для отправки письма
Параметр | Описание |
html string |
Текст с содержанием HTML разметки. |
text string |
Текст письма. |
subject string |
Тема письма. |
from_email string |
Email отправителя. |
from_name string |
Имя отправителя. |
to array |
Массив элементов “to”, содержащих данные об отправителе. |
array |
Массив элементов “global_merge_vars”, содержащих глобальные данные о метках шаблона. |
merge_vars array |
Массив элементов “merge_vars”, содержащих данные о метках шаблона. |
subaccount string |
Уникальный идентификатор субаккаунта. |
attachments array |
Массив вложений добавляемых к письму. |
images array |
Массив изображений добавляемых к письму. |
Структура параметра массива to | |
---|---|
email string |
Email адресата. |
name string |
Имя адресата. |
type string |
Тип заголовка. По умолчания используется “to”. Возможные варианты (to, cc, bcc). |
Структура параметра массива global_merge_vars | |
name string |
Имя переменной, чувствительность к регистру. Имя переменной не может начинаться с символа “_”. |
content string |
Значение переменной. |
Структура параметра массива merge_vars | |
rcpt string |
Email адрес получателя, к которому буду применены локальные подстановочные метки шаблона. |
vars array |
Массив элементов “vars”, содержащих локальные данные о метках шаблона. Структура параметра массива “vars” идентична структуре параметра массива “global_merge_vars”. |
Структура параметра массива attachments | |
type string |
MIME type вложений. |
name string |
Имя файла. |
content string |
Содержимое файла должно быть в кодировке base64. |
Структура параметра массива images. | |
type string |
MIME type файла – должен быть изображением. |
name string |
Имя файла. |
content string |
Содержимое файла должно быть в кодировке base64. |
Таблица 2. Структура элемента массива использующегося в параметре template_content
Параметр | Описание |
name string |
Имя метки. |
content string |
Содержимое метки. |
Метод send() позволяет произвести текстовую отправку письма, а второй метод предоставляет возможность производить отправку писем с использованием, заранее созданных шаблонов. Оба метода возвращают массив со структурой данных представленной в табл. 3.
Таблица 3. Структура ответа, для каждого адресата
Параметр | Описание |
email string |
Email адресата. |
status string |
Статус отправки: отправлено, в очереди, запланировано, отклонено или отправка не возможна. |
string |
Причина отказа доставки письма. Может быть, одной из следующих вариантов: rejected, hard-bounce, soft-bounce, spam, unsub, custom, invalid-sender, invalid, test-mode-limit, rule |
_id string |
Уникальный идентификатор отправленного сообщения. |
Чтобы потом не отвлекаться, создадим на будущее сразу и шаблон. Для этого в уже знакомом нам левостороннем меню кликаем по пункту “Outbound” и после перехода в соответствующий раздел, нажимаем кнопку “Create a Template”:
Здесь нам будет предложено ввести имя шаблона. После ввода такового, нажимаем кнопку “Start Coding”:
И уже на завершающем этапе нам необходимо заполнить предлагаемые поля. Затем в правом поле нужно написать код для будущего нашего подстановочного шаблона. Обратите внимание на то, что редактор шаблона должен находиться в режиме “HTML”. После заполнения всех необходимых нам полей, нажимаем кнопку “Publish”:
Теперь, когда уже все настроено, можно производить отправку письма. Исходный код отправки письма:
// Подключение библиотеки Mandrill
require_once ('Mandrill.php');
$mail = new Mandrill('API key');
/* Блок динамического контента */
$tpl_con = array(
array(
'name' => 'my-label',
'content' => '<h2>Моя рассылка</h2>'
)
);
$data = array(
'html' => 'It is html text',
'text' => 'It is simple text',
'subject' => 'Hi friend',
'from_email' => 'friend@example.com',
'from_name' => 'Michael',
'to' => array(
array(
'email' => 'example@gmail.com',
'name' => 'Lucas',
'type' => 'to'
)
),
'global_merge_vars' => array(
array(
'name' => 'NAME',
'content' => 'Lucas'
)
),
'merge_vars' => array(
array(
'rcpt' => 'example@gmail.com',
'vars' => array(
array(
'name' => 'NAME',
'content' => 'Lucas'
)
)
)
),
'attachments' => array(
array(
'type' => 'application/pdf',
'name' => 'test.pdf',
'content' => base64_encode(file_get_contents('test.pdf'))
)
),
'images' => array(
array(
'type' => 'image/png',
'name' => 'Smiley.png',
'content' => base64_encode(file_get_contents('Smiley.png'))
)
),
'subaccount' => 'cust-123'
);
try {
/* Отправка обычного письма */
$result = $mail->messages->send($data);
print_r($result);
/* Отправка письма с использованием шаблона */
$result = $mail->messages->sendTemplate('example', $tpl_con, $data);
print_r($result);
} catch(Mandrill_Error $error) {
echo 'Error: ' . get_class($error) . ' - ' . $error->getMessage();
}
Результаты работы двух методов представлены ниже. На нижнем изображении виден результат применения шаблона.
Мы отправили одно и то же письмо с использованием обоих доступных нам методов. Для того чтобы можно было увидеть отличия. В качестве примера к письму были прикреплены изображение и документ в формате PDF
Также была продемонстрирована работа с динамическим контентом и шаблонами. Разница в использовании шаблона от динамического контента состоит в том, что для шаблона указывается метка.
Данная метка в будущем будет заменена на ее содержание. А для динамического контента в HTML теге указывается следующий атрибут.
где, section-name – уникальный идентификатор, означающий, что данные указанного идентификатора будут вставлены в содержащий его HTML тег. Так же стоит учесть, что элементы шаблона указанные в поле “global_merge_vars” (см. табл. 1), будут заменены на соответствующие элементы, указанные в поле “vars” структуры “merge_vars” для указанных email адресов в поле “rcpt” структуры “merge_vars”.
Рассмотрим следующий пример:
'to' => array(
array(
'email' => 'example_1@gmail.com',
'name' => 'Lucas 2',
'type' => 'to'
),
array(
'email' => 'example_2@gmail.com',
'name' => 'Lucas 1',
'type' => 'to'
)
),
'global_merge_vars' => array(
array(
'name' => 'NAME',
'content' => 'Lucas'
)
),
'merge_vars' => array(
array(
'rcpt' => 'example_1@gmail.com',
'vars' => array(
array(
'name' => 'NAME',
'content' => 'Alex'
)
)
)
)
Здесь переопределение метки произойдет только для получателя с адресом “example_1@gmail.com”. Соответственно метка в шаблоне с именем “NAME”, будет заменена на имя “Alex”, для остальных получателей содержание метки останется “Lucas”.
При использовании обоих методов для отправки писем необходимо учитывать следующие факторы:
- При использовании метода send():
- Если в структуре данных (см. табл. 1) указано поле “html” и оно содержит некие данные, то поле “text” будет им перекрыто.
- При использовании метода sendTemplate():
- Если в редакторе шаблонов (см. выше) шаблон имеет формат “HTML”, то ни одно из двух полей: “html” и “text” не сможет перекрыть текст шаблона;
- Если в редакторе шаблонов, шаблон имеет формат “Text”, то для его автоматической подстановки в шаблон письма при отправке, запрещено указывать в структуре данных поля: “html” и “text”. Вернее указывать можно, но они не должны содержать никаких данных, иначе в тело письма пойдут данные указанные в одном из двух полей в порядке приоритета (html, text);
- Если в шаблоне не заполнить поле “subject”, то приоритет перейдет к одноименному полю (при наличии такового) в структуре данных (см. табл. 1).
Перечень возможных ошибок содержится в табл. 4.
Таблица 4. Перечень возможных ошибок, при неудавшейся отправке письма
Invalid_Key | Неверный API ключ. |
Unknown_Message | Идентификатор сообщения не существует. |
ValidationError | Параметры, переданные при вызове, являются некорректными. |
GeneralError | Произошла ошибка во время запроса. |
Комментарии (12)
IDVsbruck
26.04.2015 14:25+2Не так давно создавали аналогичный сервис, правда, для внутреннего использования компании. Как ориентир, использовали готовые почтовые сервисы, аналогичные рассматриваемому. У нас был список из 14 сервисов. Наиболее удобным и совершенным выглядит в этом списке Mailgun. Mandrill занимает только вторую строчку — тоже весьма удобен и совершенен, но до лидера не дотягивает.
Недостатки всех без исключения — достаточно слабая поддержка в работе с атачментами, отсутствие или слабая поддержка почтовых конверторов (хотя не исключаю, что они просто надежно спрятаны в коммерческих версиях), полное игнорирование алгоритмов шифрования писем типа PGP/GPG (это очень востребованный инструментарий, но его почему-то неактивно внедряют), негибкая авторизация — сомнительная возможность имплементировать свой алгоритм авторизации.vma
27.04.2015 12:00Спасибо за наводку на Mailgun.
В области защиты/подписи электронных писем S/MIME несколько более распространён, нежели PGP.
А какие «свои» алгоритмы авторизации хочется внедрять? Ведь лучше использовать стандартные проверенные, а не свои самопальные.IDVsbruck
27.04.2015 14:28Ну да, насчет «самопальный» — это несколько огульно. Речь, скорее, об альтернативах существующей токенной авторизации, когда онлайн или через АПИ получаешь рабочий токен и можешь с ним работать. Если процесс авторизации не прямой (к примеру, у нас централизованный сервис авторизации для всех продуктов компании), то это не очень удобно (я сейчас не буду вдаваться в подробности, но сделать быстро и удобно не получилось). Второе ограничение — используя один аккаунт на сервисе, используем токен(ы) для всего акка, а хотелось бы разграничения ролей при доступе к одному акку, что в обозреваемых сервисах не было доступно. Весьма заманчивой также выглядела бы реализация OAuth2 в сервисах (уверен, на сегодняшний день она есть у кого-то, но на момент обзора год назад этого не было ни у кого из рассматриваемых).
t1gor
30.04.2015 00:32Все круто, сервис действительно удобный. Не понятно только зачем документацию переводить. Хоть тег поставьте, что ли.
prishelec Автор
30.04.2015 00:43Наиболее подходящие теги вроде бы добавил. Еще есть еще предложения у вас?
Зачем переводить документацию? Отвечу. На удивление статей в «рунете» по mandrill не было (а может просто не нашел). У меня изначально были вопросы по использованию шаблонов (разница между динамическим контентом и заменяемыми метками). Некоторые называют работу с шаблонами — эта работа с динамическими блоками, а некоторые на оборот. Поэтому возникла идея написать статью для внесения ясности. Возможно кому ни будь поможет сэкономить время.
NeonSunlight
02.05.2015 14:46Сервис действительно замечательный, однако есть одно важное «но», которое перечеркивает все его достоинства для нашего проекта — письма доходят медленно.
Отправляем через smtp. В логах API письмо появляется сразу, а в логах Outbound оно может появиться только через несколько минут, а реально идти может вплоть до получаса.
На stackoverflow есть подобный вопрос, но ответа на него до сих пор нету.t1gor
03.05.2015 12:14Так в этом же вся суть асинхронной отправки
NeonSunlight
03.05.2015 15:23Т.е. для отправки срочных писем он не годится?
Тогда подскажите пожалуйста сервис для надежной отправки почты, который бы доставлял письма быстро и при этом хорошо работал со статусами писем, а также — спамом и т.д.IDVsbruck
03.05.2015 23:04Уверен, у него есть нотификаторы, стандартный перечень которых извещает о получении новой почты, изменении папок и т.д. Другое дело, что это часть АПИ, с которым обычно работает собственное приложение или адаптированный софт. Внешние готовые решения типа Outbound могут иметь таковую… а могут не иметь.
На то это и не почтовый сервер, а почтовый сервис, который ориентирован на использование своего АПИ.
К примеру, в своем продукте у нас был нотификатор, который немедленно извещал клиент о получении нового письма (если он подписан на получение извещений). Соответственно, клиент либо показывал сообщение, что письмо пришло — пользователь должен обновить окно, либо клиент автоматически посылает запрос на получение новых писем (обычное поведение онлайн-клиентов). В любом случае, этот процесс не происходит автоматом.
В твоем случае пауза перед получением новой порции писем вызвана тем, что обычно клиенты имею функцтонал опроса родительского сервиса на предмет поддержки сессии/токена, получения новой почты и прочего сопутствующего функционала. Вот и получается, что если опрос стоит на полчаса, то реально пауза может быть от 0 до 30 минут, смотря в какой момент задержки таймера прийдет письмо. Аналогия — старые версии MS Outlook, у которых по дефолту стояло 2 минуты для поллинга — новые письма были доступны либо после рефреша, либо по таймеру.
HunterNNm
Давно работаю с Mandrill, удобный сервис и API, буквально утром настраивал один проект. До этого поправлял несколько других. Хотелось бы отметить то, о чём забывают многие при передаче файлов: при кодировании в base64 размер файла увеличивается примерно на треть, после чего возникают ошибки отправки… У них вроде как помечено, но не уверен.