Отправка прайс‑листа по веб‑форме Bitrix: статусы, cron и файл во вложении
Сценарий
Сайт собирает e-mail через модуль Веб‑формы; сохранённые ответы в статусе «новый» дорабатывает cron из CLI: отправляет файл прайса письмом и переводит статус в «отправлено», как было в источнике .ru, переформулированном здесь.
Отложенная отправка спасает HTTP‑ответ от ожидания SMTP и упрощает логирование ошибок транспорта.
Форма и два статуса
Нужна форма с вопросом на e‑mail (запомните символьный SID поля — например mail или email) и два статуса результата для цепочки «ожидает рассылки» → «файл ушёл».
Почтовый шаблон
Тип события задаёт код вроде PRICE_FROM_FORM. В заголовках шаблона:
#DEFAULT_EMAIL_FROM#в поле от кого;#USER_EMAIL#или другой символьный код во «Кому» — тот же ключ передаём в массиве ниже какUSER_EMAIL.
Один файл — много получателей за прогон
Для всех результатов с «новым» статусом за один проход один раз сохраняем прайс в таблице файлов через CFile::SaveFile, переиспользуем $fileId в CEvent::SendImmediate, в конце снимаем регистрацию CFile::Delete($fileId). Связка с общей моделью — в статье о почтовых событиях.
Пример скрипта (только CLI)
Ставьте задачу в cron на пользователя, у которого есть чтение по пути к прайсу. Пути настроены под файл внутри дерева сайта как в оригинале: $_SERVER['DOCUMENT_ROOT'] — родитель текущего каталога скрипта (cron/send.php в корне).
<?php
declare(strict_types=1);
if (php_sapi_name() !== 'cli') {
die('Access denied');
}
$_SERVER['DOCUMENT_ROOT'] = dirname(__DIR__);
define('LANGUAGE_ID', 'ru');
define('NO_KEEP_STATISTIC', true);
define('NOT_CHECK_PERMISSIONS', true);
require $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_before.php';
CModule::IncludeModule('form');
final class FormMailer
{
public function __construct(
private int $formId = 15,
private int $statusNewId = 18,
private int $statusSentId = 19,
private string $attachFile = '/var/www/example.org/upload/price.xlsx',
private string $attachName = 'price.xlsx',
private string $formMailSid = 'mail',
private string $mailFrom = 'info@example.org',
private string $uploadDir = 'pricelist',
private string $eventName = 'PRICE_FROM_FORM',
private string $siteId = 's1',
) {
if (!is_readable($this->attachFile)) {
throw new RuntimeException('File not found: ' . $this->attachFile);
}
}
public function run(): void
{
$filtered = '';
$list = CFormResult::GetList(
$this->formId,
's_timestamp',
'desc',
['STATUS_ID' => $this->statusNewId],
$filtered,
'N',
false
);
if (!$list || $list->SelectedRowsCount() === 0) {
return;
}
$fileId = (int) CFile::SaveFile(
[
'name' => $this->attachName,
'tmp_name' => $this->attachFile,
'old_file' => '0',
'del' => 'N',
'MODULE_ID' => '',
'description' => '',
],
$this->uploadDir,
false,
false
);
if ($fileId <= 0) {
fwrite(STDERR, 'CFile::SaveFile failed' . PHP_EOL);
return;
}
while ($row = $list->Fetch()) {
try {
$this->notify((int)$row['ID'], $fileId);
CFormResult::SetStatus((int)$row['ID'], $this->statusSentId, 'N');
} catch (Throwable $e) {
fwrite(STDERR, 'Result #' . (int)$row['ID'] . ': ' . $e->getMessage() . PHP_EOL);
}
}
CFile::Delete($fileId);
}
private function notify(int $resultId, int $fileId): void
{
$resultStub = [];
$answerStub = [];
$data = CFormResult::GetDataByID(
$resultId,
[$this->formMailSid],
$resultStub,
$answerStub
);
$email = trim((string)($data[$this->formMailSid][0]['USER_TEXT'] ?? ''));
if ($email === '' || filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
throw new RuntimeException('empty or invalid email');
}
$event = new CEvent();
$event->SendImmediate(
$this->eventName,
$this->siteId,
[
'USER_EMAIL' => $email,
'DEFAULT_EMAIL_FROM' => $this->mailFrom,
],
'N',
'',
[$fileId]
);
}
}
(new FormMailer())->run();
- Значения свойств класса синхронизируйте с админкой: ID формы, SID поля почты и ID статусов.
- При желании ошибку по некорректному e-mail переводят в отдельный статус результата, а не в пустой
catch.
Итог
Цепочка: форма сохранилась → cron поднял файл и почту по новым результатам → статус закрывает повторную отправку тем же файлом при следующих проходах.
Не хотите копаться сами?
Починю за 1-3 дня. Без предоплаты — оплата по результату.
15+ лет опыта с 1С-Битрикс · Без предоплаты · 7 дней гарантии