К содержанию

Отложенная отправка писем при помощи 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
2 569
Реклама

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

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

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

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

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

      Николай Савин
      Николай Савин Администратор
      29 июня 2023, 08:47
      Да верно. Мы заменяем хук 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
        >> Чтобы письма отправлялись в разное время, нужно просто перебрать email и каждому поставить свою задачу.
        Но проблема в том, что мы заранее не знаем почту клиента.
          Николай Савин
          Николай Савин Администратор
          29 июня 2023, 09:10
          Заполненные поля формы доступны в параметре $params['fields']. Достаньте email оттуда, нет проблем.
            Александр Быковский
            29 июня 2023, 10:38
            Николай, прошу прощения за может быть нелепый вопрос, но могу ли я сделать третью отправку с задержкой отдельным хуком. А email и FormItAutoResponder оставить в вызове FormIt как есть. Там проблема в том, что клиенту отправляются два разных по содержанию письма, а параметр fiarTpl я поменять не могу(
              Николай Савин
              Николай Савин Администратор
              29 июня 2023, 10:41
              Можете. Общий Принцип взаимоотношений с менеджером очередей я показал. Доступ к настройкам сниппета, к полям формы есть. Крутите ими как хотите, все данные для этого доступны.
      Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
      8