Отложенная отправка писем при помощи FormIT + Scheduler

Сегодня в нашем телеграм-чатике задали вопрос —
Можно ли как то реализовать отложенную отправку письма, через форму formIT.

Этот вопрос напомнил мне о моих планах, написать инструкцию именно об этом.
По сути подобная задача уже реализована в miniShop2 на базе компонента Scheduler, не так давно опубликованного в Modstore.pro.

Итак, давайте разберемся как же все таки отправить отложенное письмо при помощи FormIt + Scheduler


Как отправлять письма используя FormIt — все знают. Вызываем сниппет FormIT (или, использующие его компоненты ajaxForm, FetchIT). В качестве хука указываем email, который берет на себя функционал мгновенной отправки писем. Если нужно отложить отправку, то напишем свой хук, который будем подключать вместо email;

Шаг 1



Создадим пару сниппетов, необходимых на следующих шагах

scheduler_hook

Это хук, который будем подключать в вызов ajaxForm, вместо email

<?php

/** @var Scheduler $scheduler */
$path = $modx->getOption(
    'scheduler.core_path',
    null,
    $modx->getOption('core_path') . 'components/scheduler/'
);
$scheduler = $modx->getService('scheduler', 'Scheduler', $path . 'model/scheduler/');
$task = $scheduler->getTask('formit', 'form_email');

// Перечисляем какие поля вы заполняете в сниппете, из тех что требуются для отправки писем
$fields = [
    'emailTo',
    'emailSubject',
    'successMessage',
    'fields'
];
$params = [];
foreach($fields as $key) {
    if (!empty($scriptProperties[$key])) {
        $params[$key] = $scriptProperties[$key];
    }
}

if ($task instanceof sTask) {
     // Здесь можете указать через какое время выполнить задание.   
    // + 1 second - мгновенно,  + 2 minutes,  + 3 hours. 
    //  Также допустимы точные указания времени
    $task->schedule('+1 second', $params);
} 

return true;

send_email

Это сниппет, который позже в фоновом запланированном режиме будет отправлять письмо

unset($scriptProperties['task']);
unset($scriptProperties['run']);
$scriptProperties['hooks'] = 'email';
$_POST = $scriptProperties['fields'];
unset($scriptProperties['fields']);
$modx->runSnippet('FormIt', $scriptProperties);
if (!empty($scriptProperties['successMessage'])) {
    return $scriptProperties['successMessage'];
}
return 'done';


Шаг 2



Далее настроим компонент Scheduler. После установки, перейдите в него, откройте вкладку задания и нажмите создать задание



Заполним задание следующим образом:

  • Название — любое произвольное на английском. Я назвал form_email
  • Тип задания — на основе сниппета
  • Категория — formIT
  • Сниппет — созданный на шаге 1 сниппет send_email
Сохраняем



Шаг 3



Замените в вызове formIT или ajaxForm хук email на хук scheduler_hook

После отправки формы, в вашем планировщике должно появиться задание, в котором будет видно заполненные данные клиента, что само по себе уже является плюсом и позволяет отслеживать письма и их содержимое



Шаг 4


Обратите внимание на, то, что компонент запускается сервером через серверный планировщик задач CRON
Чтобы выполнение отложенных задач работало — нужно добавить CRON запись на вашем хостинге. Как это сделать описано в документации Scheduler
Николай Савин
27 июня 2023, 19:24
modx.pro
6
1 135
+14
Поблагодарить автора Отправить деньги

Комментарии: 8

Дима Касаткин
27 июня 2023, 20:04
+3
Классный хак с повторным вызовом FormIT и пробросом туда параметров из задания через $_POST, очень элегантно!

Мне вот на подобие этого нужно было как-то вызывать хук для формита с API-вызовами к внешнему сервису но без отправки формы, так пришлось его код копировать и в сниппет выносить, а стоило сделать вот так как в заметке сделан сниппет send_email, чтобы не дублировать код и не поддерживать потом 2 версии…

К стати дополню список — в AjaxFormitLogin этот метод тоже будет работать
Александр Быковский
29 июня 2023, 07:49
0
Николай, правильно ли я понимаю, что этими действиями мы заменяем хук email и отправка писем (хуки email + FormItAutoResponder) будут откладываться на заданное время?

А если ситуация такая когда отправляются 3 письма: Заявка ушла админу/менеджеру, непонимание ушло клиенту — это всё мгновенно должно уходить после отправки формы. А третье через 15 минут уходит опять же клиенту.
Как на схеме, как прикрутить этот компонент? Заранее благодарен

    Николай Савин
    29 июня 2023, 08:47
    +1
    Да верно. Мы заменяем хук email. Насчет хука FormItAutoResponder…
    В сниппете send_email в список выполняемых хуков нужно просто добавить все нужные хуки.

    Чтобы письма отправлялись в разное время, нужно просто перебрать email и каждому поставить свою задачу. Перепишем кусок поставновки задачи вот так:

    // Перечисляем какие поля вы заполняете в сниппете, из тех что требуются для отправки писем
    $fields = [
        'emailTo',
        'emailSubject',
        'successMessage',
        'fields'
    ];
    $params = [];
    foreach($fields as $key) {
        if (!empty($scriptProperties[$key])) {
            $params[$key] = $scriptProperties[$key];
        }
    }
    
    if ($task instanceof sTask) {
        $emails = $params['emailTo'];
        unset($params['emailTo']);
        $emails = array_map('trim', explode(',', $emails));
        foreach($emails as $email) {
            $params['emailTo'] = $email;
            // Здесь можете указать через какое время выполнить задание. 
    
            switch($email) {
                case 'bigboss@mail.ru':
                    //   Этому отправляем сразу
                    $task->schedule('+1 second', $params);
                case 'smallboss@mail.ru':
                    //   Этому отправляем через 5 минут
                    $task->schedule('+5 minutes', $params);
                break;
            }  
        }
       
    }
      Александр Быковский
      29 июня 2023, 09:07
      0
      >> Чтобы письма отправлялись в разное время, нужно просто перебрать email и каждому поставить свою задачу.
      Но проблема в том, что мы заранее не знаем почту клиента.
        Николай Савин
        29 июня 2023, 09:10
        +1
        Заполненные поля формы доступны в параметре $params['fields']. Достаньте email оттуда, нет проблем.
          Александр Быковский
          29 июня 2023, 10:38
          0
          Николай, прошу прощения за может быть нелепый вопрос, но могу ли я сделать третью отправку с задержкой отдельным хуком. А email и FormItAutoResponder оставить в вызове FormIt как есть. Там проблема в том, что клиенту отправляются два разных по содержанию письма, а параметр fiarTpl я поменять не могу(
            Николай Савин
            29 июня 2023, 10:41
            +1
            Можете. Общий Принцип взаимоотношений с менеджером очередей я показал. Доступ к настройкам сниппета, к полям формы есть. Крутите ими как хотите, все данные для этого доступны.
    Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
    8