MODX - Создание email рассылки
Статья, в которой рассмотрим, как на базе компонента Sendex организовать еженедельную email рассылку писем подписчикам сайта.

Создание email рассылки для MODX Revolution на основе дополнения Sendex будет состоять из следующих основных шагов:
- установка компонента Sendex;
- создания email шаблона письма;
- создания подписки;
- разработки ресурса, на котором зарегистрированный и анонимный пользователь смогут не только подписаться на email рассылку, но также отписаться от неё;
- создания php скрипта
create.letters.php
для автоматического формирования основного содержимого email рассылки и очереди писем для отправки; - настройки планировщика cron, который будет запускать в определённые моменты времени файлы
create.letters.php
иsend.php
.
Установка компонента Sendex
Установка компонента Sendex осуществляется через поставщика modstore.pro. Если он у вас не установлен, то сначала создайте его. После этого загрузите и установите для CMS MODX Revolution дополнение Sendex.
Создание email шаблона письма
Разрабатывать рассылку начнём с создания шаблона. Он необходим для создания HTML структуры (email шаблона) письма. В качестве имени зададим ему, например, значение SendexTemplate
.
Содержимое шаблона (пример):
<table style="background-color: #f1f1f1; width:100%; font-family:-apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;" align="center" width="100%" border="0" cellpadding="0" cellspacing="0"> <tbody> <tr> <td align="center" style="vertical-align:top;padding:30px 0;text-align:center"> <table style="text-align:left;width:680px;margin:0 auto;font-size:14px;border-spacing:0px"> <tbody> <tr> <td bgcolor="#fff" style="padding: 15px;"> <font color="#777" style="font-size:18px">[[+newsletter.name]] ([[+phx:input=`now`:strtotime:date=`%d.%m.%Yг.`]])</font> </td> </tr> <tr><td height="25"></td></tr> <tr> <td bgcolor="#fff" style="padding: 15px;"> [[+newsletter.description]] </td> </tr> <tr><td height="25"></td></tr> <tr> <td bgcolor="#fff" style="padding: 20px 15px; color: #777; font-size: 14px;"> <p>© 2017 Мой сайт.</p> <p style="font-size: 12px;">Это сообщение было отправлено на [[+subscriber.email]] потому, что вы подписались на еженедельную рассылку. Данное письмо не требует ответа.</p> <p style="font-size: 12px;">Если вы не хотите больше получать письма от нас, то щелкните <a href="[[~10?scheme=`full`&sx_action=`unsubscribe`&code=`[[+subscriber.code]]`]]" target="_blank">здесь</a>.</p> </td> </tr> </tboy> </table> </td> </tr> </tbody> </table>
Назначение ссылки и плейсхолдеров в содержимом шаблона SendexTemplate
:
[[+newsletter.name]]
- название подписки;[[+newsletter.description]]
- описание (основное содержимое) подписки;[[+subscriber.email]]
- email адрес подписчика;~10
- формирует ссылку на 10 ресурс сайта (этот ресурс, а точнее сниппет Sendex, расположенный в нём, будет осуществлять отписку от рассылки, если конечно пользователь перейдёт по ней);[[+subscriber.code]]
- код подписчика.
Создание рассылки
Для создания рассылки откроем в админке MODX страницу Sendex (Приложения -> Sendex). Переключимся на вкладку "Подписки" и нажмём на кнопку "Создать".

В диалоговом окне "Создать подписку" заполним поля формы следующими значениями:
- Название - Информационная рассылка;
- Шаблон -
SendexTemplate
; - Тема письма - Мой сайт - Еженедельная информационная рассылка;
- Ответный email -
no-reply@mysite.ru
; - Исходящий email -
no-reply@mysite.ru
; - Отправитель - Мой сайт.
Поле "Описание" заполнять не будем. Его наполнение будем осуществлять с помощью php скрипта create.letters.php
. Данный скрипт будем запускать с помощью планировщика cron раз в неделю.

Создание ресурса «Email подписка»
Создадим в админке MODX Revolution ресурс (pagetitle
- Email подписка).
В содержимое ресурса поместим вызов 2 сниппетов:
[[!SendexEventTracking]] [[!Sendex? &id=`1` ]]
Сниппет Sendex
Сниппет Sendex осуществляет подписку пользователя на рассылку (в данном случае ту, которая имеет идентификатор 1), а также отписку от неё.
Подписку на рассылку, а также отписку от неё авторизированный пользователь осуществляет с помощью щелчка по кнопке.

Анонимный же пользователь осуществляет подписку через ссылку в письме. Для получения письма он должен ввести свой email адрес в форму подписки и нажать на кнопку «Подписаться».

Отписка от рассылки также осуществляется с помощью ссылки, которую, например можно расположить в футере письма. Если анонимный пользователь больше не захочет получать еженедельную информационную рассылку, то ему будет достаточно просто перейти по ней. Идентификация подписчика осуществляется по коду.
Настройка вывода форм, связанных с подпиской, сниппет Sendex осуществляет с помощью параметров:
tplSubscribeGuest
- чанк (по умолчаниюtpl.Sendex.subscribe.guest
), содержащий форму, с помощью которой анонимный пользователь может подписаться на рассылку.tplActivate
- чанк (по умолчаниюtpl.Sendex.activate
), содержащий email шаблон, на основании которого будет формироваться письмо анонимному пользователю. Основное содержимое письма – это ссылка, по которой ему необходимо перейти для того, чтобы подтвердить подписку.tplSubscribeAuth
– чанк (по умолчаниюtpl.Sendex.subscribe.auth
), содержащий форму подписки, которая будет показываться авторизированному пользователю;tplUnsubscribe
– чанк (по умолчаниюtpl.Sendex.unsubscribe
), содержащий форму, посредством которой авторизированный пользователь может отписаться от рассылки.
При необходимости вы можете настроить содержимое каждого чанка. Но лучше это делать не в исходных чанках, а в их копиях, которые затем указать сниппету с помощью соответствующих параметров:
Например:
[[!Sendex? &id=`1` &tplSubscribeAuth=`tplSendexSubscribeAuth` &tplSubscribeGuest=`tplSendexSubscribeGuest` &tplUnsubscribe=`tplSendexUnsubscribe` &tplActivate=`tplSendexActivate` ]]
Сниппет SendexEventTracking
Сниппет SendexEventTracking
предназначен для отображения на странице информационных сообщений, связанных с email подпиской.
Вывод того или иного сообщения зависит от наличия в составе URL одного из следующих параметров: sx_subscribed
, sx_confirmed
, sx_unsubscribed
.
Код сниппета SendexEventTracking
:
<?php $output = ''; $subscribed = $modx->getOption('subscribed', $scriptProperties, 'tplSendexEventSubscribed'); $confirmed = $modx->getOption('confirmed', $scriptProperties, 'tplSendexEventConfirmed'); $unsubscribed = $modx->getOption('unsubscribed', $scriptProperties, 'tplSendexEventUnsubscribed'); if ($_GET['sx_subscribed']) { $output = $modx->getChunk($subscribed); } if ($_GET['sx_confirmed']) { $output = $modx->getChunk($confirmed); } if ($_GET['sx_unsubscribed']) { $output = $modx->getChunk($unsubscribed); } return $output;
Все информационные сообщения хранятся в чанках (по умолчанию): tplSendexEventSubscribed
, tplSendexEventConfirmed
, tplSendexEventUnsubscribed
.
Код чанка tplSendexEventSubscribed
(пример):
<div class="alert alert-danger">На указанный почтовый ящик отправлено письмо, содержащее ссылку. Перейдите по ссылке для подтверждения email адреса, на который будут высылаться раз в неделю новые статьи.</div>
Код чанка tplSendexEventConfirmed
(пример):
<div class="alert alert-danger">Вы успешно подписаны на еженедельную email рассылку сайта.</div>
Код чанка tplSendexEventUnsubscribed
(пример):
<div class="alert alert-danger">Вы успешно отписаны от рассылки новых статей сайта.</div>

Автоматическое формирование тела email рассылки
Формировать тело рассылки будем выполнять автоматически с помощью php файла. Для этого создадим файл create.letters.php
, например, в директории cron (/core/components/sendex/cron/) со следующим содержимым:
<?php require_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . '/config.core.php'; require_once MODX_CORE_PATH.'model/modx/modx.class.php'; $modx = new modX(); $modx->initialize('web'); $modx->getService('error','error.modError', '', ''); // id раздела, в котором расположены статьи $parent = array(5,6,7); // создадим запрос на выборку новых статей, расположенных в указанных разделах (дата публикации не позже 7 дней) $query = $modx->newQuery('modResource', array( 'publishedon:>=' => strtotime('-7 days'), 'parent:IN' => $parent )); // ограничим выборку 5 элементами $query->limit(5); // получим статьи $resources = $modx->getCollection('modResource', $query); $output = ''; // переберём статьи и сформируем ответ foreach ($resources as $resource) { $id = $resource->get('id'); $pagetitle = $resource->get('pagetitle'); $description = $resource->get('description'); $url = $modx->makeUrl($id,'','','https'); // получим tv поле image (id=2) $image = $modx->getObject('modTemplateVarResource',array( 'tmplvarid' => 2, 'contentid' => $id )); if (is_object($image)) { $image = 'http://mysite.ru/assets/images/'.$image->get('value'); } else { $image = ''; } $output .= $modx->getChunk('tpl.newsletter.article',array( 'pagetitle' => $pagetitle, 'description' => $description, 'url' => $url, 'image' => $image )); } $count = count($resources); // не будем формировать очередь, если количество новых статей равно нулю if ($count==0) { exit(); } // формируем очередь (создаём письма для отправки подписанным пользователям) $modx->addPackage('sendex', MODX_CORE_PATH . 'components/sendex/model/'); /** @var sxNewsletter $newsLetter */ if ($newsLetter = $modx->getObject('sxNewsletter', 1)) { $newsLetter = $modx->getObject('sxNewsletter', 1); $newsLetter->set('description',$output); $newsLetter->save(); $response = $newsLetter->addQueues(); } exit();
Пример чанка, который будет использовать для оформления каждой статьи в письме (tpl.newsletter.article
):
<tr> <td bgcolor="#fff" style="padding: 15px;"> <table border="0" cellpadding="0" cellspacing="0" align="left" width="100%"> <tbody> <tr> <td width="12" valign="middle" style="padding:10px 0;"> <span style="display:block;border-left:5px solid #2ecc71"> <font style="font-size:20px"> </font> </span> </td> <td valign="middle" style="padding: 10px 0;"> <font color="#2ecc71" style="font-size:20px">[[+pagetitle]]</font> </td> </tr> </tbody> </table> </td> </tr> <tr> <td valign="top" bgcolor="#fff"> <table border="0" cellpadding="0" cellspacing="0" align="left" style="width:100%;"> <tbody> <tr> <td valign="top"> <img src="[[+image]]" alt="[[+pagetitle]]" style="max-width: 100%;"> </td> </tr> <tr> <td valign="top" style="padding: 15px;"> <font color="#777" style="font-size:14px">[[+description]]</font> </td> </tr> <tr> <td align="right" style="padding: 5px 15px 10px 0px;"> <a href="[[+url]]" target="_blank"> <font color="#2ecc71" style="font-size:14px"> Читать далее...</font></a> </td> </tr> </tbody> </table> </td> </tr> <tr><td height="25"></td></tr>


Настройка cron для запуска email рассылки по расписанию
Заключительное действие - это добавление в программу-планировщик cron двух заданий для запуска их в определённое время с определённой периодичностью.
Например:
- файл
create.letters.php
(формирование писем и додавление их в очередь) - например, каждый четверг в 6 часов утра (0 6 * * 4); - файл send.php (отправка писем) - например, каждый четверг, начиная с 7 часов утра (*/12 7-9 * * 4).
Если подписчиков много, то письма можно отправлять небольшими порциями (например, по 50 штук) каждые 5 минут (*/12) в течение 3 часов (7-9). Файл send.php
необходимо запускать после выполнения файла create.letters.php
.
Содержимое файла send.php
:
<?php require_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . '/config.core.php'; require_once MODX_CORE_PATH . 'config/' . MODX_CONFIG_KEY . '.inc.php'; require_once MODX_CONNECTORS_PATH . 'index.php'; $modx->addPackage('sendex', MODX_CORE_PATH . 'components/sendex/model/'); $q = $modx->newQuery('sxQueue'); $q->limit($modx->getOption('sendex_queue_limit', null, 50, true)); // 50 - количество писем, отправляемых за один раз $queue = $modx->getCollection('sxQueue', $q); /** @var sxQueue $email */ foreach ($queue as $email) { $email->send(); }

Пример содержимого email письма (рассылки)
После отправки рассылки, каждый подписанный пользователь получит на свой адрес письмо, содержащий материал собранный create.letters.php
.

Скажите, пожалуйста, что я могу делать не так? Спасибо!
Parse error: syntax error, unexpected '[' in /home/host1604701/oartemi-slovo.ru/htdocs/www/core/model/modx/modx.class.php on line 283
в 283 строке действительно есть строка с квадратными скобками: private $loggedDeprecatedFunctions = [];
но ведь это стандартная поставка modx: htdocs\www\core\model\modx\modx.class.php
Начало create.letters.php как у Вас:
require_once dirname(dirname(dirname(dirname(dirname(__FILE__))))). '/config.core.php';
require_once MODX_CORE_PATH.'model/modx/modx.class.php';
require_once dirname(dirname(dirname(dirname(dirname(__FILE__))))). '/config.core.php';
то выходит сообщение:
Class 'modX' not found in /home/host1604701/oartemi-slovo.ru/htdocs/www/core/components/sendex/cron/create.letters.php on line 5.
понятно, что не подключен modx.class.php.
то парсер конкретно говорит не об ошибке create.letters.php, а об ошибке modx.class.php. Но это же стандартный класс, я в нём ничего не меняла, как может быть ошибка в нём?
Parse error: syntax error, unexpected '[' in /home/host1604701/oartemi-slovo.ru/htdocs/www/core/model/modx/modx.class.php on line 283
Parse error: syntax error, unexpected '[' in /home/host1604701/oartemi-slovo.ru/htdocs/www/core/model/modx/modx.class.php on line 283
Подскажите, пожалуйста, как правильно написать условие для , если нужно выбрать несколько разделов, некоторые из которых еще и контейнеры (указать глубину).
Например, разделы 1,3,5,7, из которых 3 и 5 содержат подразделы.
Про прочитал, а как поступить если таких парентов несколько, и плюс обычные разделы?
Спасибо за Ваш сайт, и за Ваш труд!
В PHP имеется функция array_merge с помощью которой слить несколько массивов в один.
Вроде всё делаю по инструкции.
Спасибо за статью!
Подскажите, пожалуйста, а можно ли с помощью Sendex отправлять письма пользователям, если их ресурс (где пользователь автор) опубликован и оповещать их, если приближается дата отмены публикации?
Для доски объявлений
Понимаю, что надо через createdby делать
Знак «не равно» записывается так:
В поле published хранится 1 или 0. Если published равно 1, то это значит, что ресурс опубликован. В createdby хранится id пользователя (число).
Только с пользователем не понятно, как по id пользователя формировать рассылку? чтобы только автору приходило письмо
Если вам это не нужно, то просто используйте modMail, который идёт вместе с MODX Revolution.
Пример, как его использовать:
Автор компонента почему-то перестал отвечать на комментарии (modx.pro)
Создал группу пользователей Sendex, в настройках minishop2 указал, что бы все новые пользователи добавлялись в эту группу.
Создал ресурс отписки от рассылки — в письме получавшему будет ссылка. Перешел, отписался.
Но как указать, что бы когда пользователь отписывается исключался из этой группы?
Смысл в том, пользователь делая заказ на сайте попадает в группу рассылки, а если не хочет получать её то нажимает ссылку в письме и исключается из группы. В Sendex нет инструментов по выбору пользователей для рассылки, или по одному всех подряд или группу, но отправлять пользователю который отписался от рассылки не правильно.
Прошу помощи.
Методы Sendex (в том числе и метод отписывающий пользователя от рассылки) находятся в файле «\core\components\sendex\model\sendex\sxnewsletter.class».
В метод unSubscribe вам необходимо дополнительно добавить код для удаления пользователя из группы.
2 — это ID этой группы
Можно ли сделать так, чтобы когда добавляется новость на сайт, то сразу рассылка была автоматически?
Вот ссылки на инфу, которой пользовался для написания:
r-band.ru/how-to/chtenie-faylov-excel-na-php-osnovnye-metody-klassa-phpexcel.html
www.createit.ru/blog/modx/2012/programmatically-creating-users
Могу скрипт продать 3000р))
письма формируются, отправляются, но остаются в очереди и по следующему запуску скрипта отправки писем снова уходят.
Подскажите как лучше сделать рассылку, где будет выборка по нескольким родителям, но для каждого из них будет свой шаблон?
Вижу 2 варианта:
1. create.letters.php сделать еще одну выборку, но тогда там нужно формировать подзаголовки для каждой выборки, что мне кажется не очень красиво
2. прописать 2 или больше подзаголовка в шаблоне SendexTemplate, но тогда я не понимаю как быть со скриптом create.letters.php он как я понял формирует и все в одно место выдает
Можно просто написать условие:
исходя из кода в зависимости от родителя будет выбран тот или иной шаблон, а мне нужно чтобы были использованы оба шаблона в одной рассылке для $parent == 5 tpl.newsletter.article, а для $parent == 6 — tpl.newsletter.article2
то есть идет текст рассылки
Например:
Содержимое чанка tpl.newsletter:
Ну, соответственно содержимое чанков tpl.newsletter.news, tpl.newsletter.article и tpl.newsletter.photo формируете так как это необходимо.
А еще вопрос — как я понимаю в текущем варианте идет выборка с глубиной 0? а как добавить глубины выборки например 5?
пробовал
и всяие
и тп — ничего не работает…
$parent = $modx->getChildIds(281,3);
где первая цифра id раздела, вторая — глубина поиска наследников с таким учетом, чтобы их дети и были нужны в выборке.
надеюсь понятно объяснил, может кому пригодится)
Скажите как можно организовать подписку не перезагружая страницу? Проблема в том, что форма с подпиской находится почти в самом низу страницы, а она не маленькая! Ситуация: ты вводишь свой e-mail страница перезагружается и вообще не понятно что происходит!?
В идеале, перезагружается этот блок и выводится сообщение из снипета SendexEventTracking вместо этой формы! Можно ли такое сделать? Если как, то куда смотреть, как организовать?
Спасибо!
Подскажите, как реализовать в
$query = $modx->newQuery('modResource', array(
'publishedon:>=' => strtotime('-7 days'),
'parent:IN' => $parent
));
что бы было равно сегодняшней дате.
'publishedon:==' => сегодня,
Идея: Создал статьи и выставил дату публикации на будущее (каждый четверг). Скрипт должен проверить в четверг найти все статьи созданные в этот день и сформировать очередь.
Сейчас он формирует все новости, ограничивается только $query->limit(5);
Надеюсь на Вашу помощь.
Все варианты условий можно посмотреть на этой странице. Они расположены в пункте, который начинается с текста «xPDOQuery.where...».
Знак «равно» задаётся так:
В вашем случае неправильно задавать такое условие, т.к. дата, скорее всего включает в себя ещё и время.
Необходимо, для выбора ресурсов с текущей датой, использовать следующее:
Не подскажите еще по одному вопросу.
Sendex останавливает работу если адрес не верный или не существующий, и приходиться запускать заново удаляя из таблицы проблемный емейл.
Может возможно перепрыгивать проблемные мейлы и отсылать дальше.
Как возможно решить этот вопрос?
$q->limit($modx->getOption('sendex_queue_limit', null, 50, true));
сейчас стоит 2.
При лимите 100 он не плохо все отправил, но мейл не любит таких.
По каким причинам еще он может просто застревать?
P.S.: В ручную по одному письму отправляет. Через send.php и cron не хочет. На той недели отправлял но запинался на проблемных.
3 видимо проблемные адреса, если сейчас встретит еще 2 проблемных работа рассылки остановится.
А именно заменить вышеприведённый блок кода на этот:
s1.bild.me/bilder/110417/4942049screenshot_2017-12-05_005.png
Возник вопрос, а выборка для еженедельной отправки делается среди новых ресурсов?
Т.е. он может на момент запуска скрипта посмотреть что нового публиковалось в какой-то категории и отправить это в рассылку? Как такое можно реализовать?
И второй вопрос, возможно ли, чтоб при добавлении статьи автоматически происходила отправка, допустим, первых двух абзацев на почту подписчикам с кнопкой «Подробнее»? Как связать sendex со статьями, чтоб он подхватывал картинку из ресурса и текст контента?
Спасибо.
Да, среди новых (на момент запуска скрипта, выбираются только те ресурсы, которые имеют дату публикации не позже 7 дней). Разделы, из которых это необходимо осуществить настраиваются с помощью переменой $parent.
Для решения второго вопроса, нужно создать плагин на событие OnDocPublished. В обработчике этого события написать код, подобный тому, который приведён в файлах create.letters.php и send.php.
Скрипт из панели Cron на Beget пробовал вручную запускать, тоже ничего не происходит. При том, что ресурсы, перечисленные в Parent младше 7 дней давности.
И еще, если имя TV картинки отличается от image, его везде надо переписать или достаточно только в теле шаблона tpl.newsletter.article?
И что делать с send.php? Судя по статье Cron должен стартовать только первый скрипт? Или создать задания надо на оба файла?
Выбор TV картинки в скрипте выполняется по id, т.е. имя TV не используется.
В примере id TV имеет значение 2:
Снчала должен запускаться скрипт create.letters.php. Он формирует письма и добавляет их в очередь. После него send.php. Он отправляет их.
Категории новостей с ресурсами в виде коллекции.
п.с. тоже не получается передать TV в тело письма (((
Для этого создаём php-файл, например, «letters.php» в корне сайта:
Открываем его браузере и проверяем.
Что делаю не так?
Попробуйте просто вывести значения на экран:
Чанки:
tpl.newsletter.article.tpl
tpl.newsletter.wrapper.tpl
На месте, и заполнены
Весь мой код этой страницы:
В чанке «tpl.newsletter.wrapper.tpl» плейсхолдер [[+newsletter.description]] необходимо заменить на {$output}, т.к. он используется в коде.
Теперь осталось понять, почему мои TV не выводятся
У меня в форме обратной связи на сайте чекбокс «подписаться на новости».
Решил сделать хук для Formit.
Проверку на подписанность юзера в таблице sendex'а сделать вроде соображу как.
А как из этого сниппета запустить sendex, чтобы он отработал так же, как при нажатии кнопки «подписаться» подскажите?
В этом случае вам необходимо самостоятельно организовать логику, используя методы Sendex.
Например:
И непонятно как прописать время рассылки в файле: create.letters.php?
Выборка ресурсов осуществляется с помощью следующего кода:
Проверьте, опубликованы ли созданные ресурсы. А также корректно ли вы выставили значение переменной $parent.
Время рассылки настраивается с помощью cron, а не в файле. Файл create.letters.php не может сам себя запустить. Его запуск осуществляет планировщик cron.
($_lang['sendex_menu_desc'] = 'Newsletters management'; — так нужно)
То есть, как его на английский перевести, чтоб все предупреждения типа «введите emal», на английском были.
Но при нажатии на кнопку, подписать, закрывается модальное окно! Как сделать чтоб окно не закрывалось, при нажатии на кнопку отправить?
Сделал так:
[[!AjaxForm?
&form=`tplSendexSubscribeGuest`
&snippet=`Sendex`
&id=`1`
]]
Ничего не работает!
Например, у вас есть контекст сайта на английском языке. В настройки это контекста вы добавляете параметр cultureKey со значением en.После этого вся информация у вас на сайте будет отображаться на английском языке.
Вопросы чуть поподробнее.
1.Куда вставить этот чанк??
Пример чанка, который будет использовать для оформления каждой статьи в письме:
2. Как создать эту задачу??
Пример создания новой задачи для cron с помощью панели управления виртуальным хостингом
Спасибо за сайт.
1. Данный чанк должен иметь имя tpl.newsletter.article.
2. Это зависит от хостера. Необходимо в его справке найти соответствующий раздел и посмотреть, как это делается. Вот пример справки от Beget: _https://beget.com/ru/manual/crontab
Хотела реализовать на практике не ному справиться с приложением sendex.
Помогите пожалуйста разобраться!
На вкладке Пакеты Sendex не активный, при переходе в приложение ничего не происходит
itchief.ru/assets/uploadify/2/a/4/2a4ba9bd8c6f1b388e70f2d792f1a9a7.jpg