Давняя головная боль, которую все преодолевают по разному. Я нашел такой вот путь, надеюсь кому-нибудь еще пригодится [spoiler] Итак, небольшой ликбез почему так, а не иначе.
Что дано - после того как отправляется письмо с CEvent::Send() оно на самом деле сначала добавляется в таблицу b_event как событие и сработает на следующем хите (фактически на вашем же) - перед добавлением в таблицу вызывается обработчик OnBeforeEventAdd - после добавления в таблицу (на следующем хите) происходит уже отправка письма; как и что там происходит описывать не буду, потому что туда нам не вклинится - там есть обработчик OnBeforeEventSend, но он вызывается, когда письмо уже формируется, фактически перед отправкой и поздно что-то делать.
Вывод: вклиниться надо в OnBeforeEventAdd.
Скачиваем файл с единственной функцией SendAttache() для отправки нашего письма. Внимание! Функция не предусматривает отправки письма без файла. Складируем ее к себе, подключаем файл (я подключил его в момент отправки письма, чтобы постоянно не копилило).
$event, $lid, $arFields передаются по ссылке - их изменение повлечет изменений изначальных переменных. На этом мы и сыграем далее.
В первой строчку я подключаю тот самый файл. Во второй строчке вызываю функцию из файла (переменные те же, что передаются в обработчик + аттач).
А вот третья строчка это чистой воды танец с бубном. Если этого не сделать, то придет два письма по шаблону. Почему? Потому что после обработчика идет добавление в таблицу b_event (см. выше). Но мы то письмо уже отправили (обращаю внимание, что при отправке нашим способом добавления в таблицу не происходит). Значит нам надо сделать так, чтобы будущее добавление в таблицу не повлекло отправку письма. unset у меня почему-то не сработал, поэтому я просто присвоил null.
Вот собственно и все. Хочу заметить, что если в SendAttache четвертым параметром передать не путь, а массив путей, то к письму приложится несколько аттачей.
В обработчике лишь пример как можно использовать данную функцию. Логика у каждого своя, поэтому я не стал изощряться.
UPD По поводу $event = 'null' пару слов еще. Дело в том, что добавление в таблицу произойдет, но система помаркирует ее как "провал при отправке" и письма не отправится, а через несколько дней запись и вовсе удалится автоматически.
Оба ошибаетесь В настройках главного модуля есть опция "Сколько писем отправлять за один хит:". Если на данном хите нужно отправить столько писем, или менее, они отправятся сразу же. Иначе на следующих хитах.
Это верно для модуля "Рассылки", в нём - в том же хите проставляется статус "в процессе", далее формируется список адресатов, отсылается максимально возможное число писем, остальные будут отосланы уже на других хитах и не обязательно этого же пользователя! Что же касается CEvent::Send(), то он отрабатывается на том же хите.
Его первый запуск обработается на этом же хите если отправлять можно пачками по 5 писем, а в очереди 7, то на этом же хите отправится 5, а на следующем 2.
Иначе как вы представляете себе отправку уведомления о новом сообщении в теме, на которую подписалось 1000 человек.
Совершенно верно. CEvent::Send() работает по тому же принципу, как и модуль рассылок. Я когда-то на этом обжегся.
Легко убедиться, посмотрев в исходники. CEvent::Send() просто добавляет запись в таблицу b_event. А уже CEvent::CheckEvents(), которая выполняется в конце каждого хита, получает определенное количество писем из b_event (по умолчанию 5) и отправляет.
Нашел причину: вы, скорее всего, подключаете файл по неправильному пути (относительно корня сервера). Необходимо делать это относительно корня сайта: /bitrix/components/bitrix/mycomponent/user.xml
Добрый день! Спасибо за пост, единственное решение, которое удалось найти, но постигло разочарование - на версии 9.5.9 не работает. Все сделал, как описано выше, пути правильно прописал. Может быть есть какие то соображения относительно того, почему на этой версии не работает??? Заранее спасибо
Антон, прошу прощения, взбаламутил воду раньше времени. В общем мне нужно было отправлять логотип сайта в почтовых событиях стандартных, битриксовых, которые выполняются ядром (например при восстановлении пароля и отправке контрольной строки). Суппорт разъяснил, что ядро в этом случае выполняет не CEvent::Send, а CEvent::SendImmediate в котором обработчика OnBeforeEventAdd нет ((( Очень жаль. Остается ждать выхода 10ки, в которой, как обещали на партнерке, будет реализован функционал приаттачивания файлов к почтовым событиям.
Антон, спасибо! Воспользовался :)Есть одно замечание с которым не удалось разобраться - отправка дублирующего сообщения на емейл указанный в "E-Mail адрес или список адресов через запятую на который будут дублироваться все исходящие сообщения". Хотелось бы исключить отправку таких писем с атачем. Сам вызов CEvent::Send() в 4-м параметре передаю "N", но все равно дубль отправляется. Не подскажете как победить этот момент?
Странности были при тестировании данного функционала в тестовом хостинге. Все работало. Но при переносе на рабочий сайт письмо не отправлялось. При этом хостинг уже другой. Заработало при коррекции скрипта mail_attach.php:
$head .= "boundary=\"----".$un."\"".$eol.$eol;
поменяли на:
$head .= "boundary=\"----".$un."\"".$eol;
Разумного объяснения дать не могу. Если у кого есть соображения по этому поводу интересно было бы их услышать
Антон, приветствую. Спасибо за наводку, однако, как только скормили его в IDE получили 3 неопределенных переменных и завязанный на них функционал. Вопрос: нужно ли это?
$cSearch = count($arSearch);
foreach ($arSearch as $id => $key)
{
$strCFields .= substr($key, 1, strlen($key)-2)."=".$arReplace[$id];
if ($id < $cSearch-1)
$strCFields .= "&";
}
// Не определены $arSearch, $arReplace
$head .= "X-MID: $messID.".$arMessTpl["ID"]."(".date($DB->DateFormatToPHP(CLang::GetDateFormat("FULL"))).")".$eol;
// Не определен $messID.
После обновления на 12.0 столкнулась со следующей проблемой - отправляется 2 письма: с вложением и без. Т.е. возможно эвент отправки простого письма не отменяется ($event = 'null'). Можете подсказать, пожалуйста, как исправить данную проблему?
AddEventHandler("main", "OnSendUserInfo", Array("MyClass", "bxModifyRegistretionMails"));
class MyClass
{
function bxModifyRegistretionMails(&$arParams){
/*******************************************/
SendAttache($arParams["EVENT_NAME"], $arParams["SITE_ID"], $arParams, $filePath);
unset($arParams);
}
Письмо с аттачем не получает поля из arParams и как тут отменить письмо стандартное ? А то приходит одно письмо стандартное(неизмененное) и второе с вложением но не подставляются вместо #КОДА# значения .
Кирилл, данное событие не перехватить. Ибо оно улетает сразу, не ложась в базу. Только переопределять custom_mail. Может получится как-то зацепиться за событие OnBeforeEventSend. Но не уверен.
Назар, если это не локальная проблема почтовика, которым открываете eml-файл, и не проблема самого файла, то надо изучать заголовки письма, почему именно проблема, и какая. Удаленно ничего не скажешь абсолютно.
Антон, а как можно реализовать, чтобы на почту приходил не прикрепленный файл, а ссылка на него? Сначала формируется сообщение для email, потом создается элемент, файл прикрепляется к элементу
Можно еще расширить функцию добавив $message_id, чтобы могли отправляться разные шаблоны одного типа.
У меня, кстати на 14.5 null-ы не сработали. Упорно 2 письма уходило, пока я сами шаблоны не сделал неактивными. Событие OnBeforeEventAddHandl при этом срабатывает, а отправка штатными средствами уже - нет.
есть такая особенность, из-за которой я немного подзастрял, не мог понять почему не работает: в методе CEvent::Send в параметре $lid можно передавать как id сайта, так и массив id сайтов. А функция SendAttache в одноименном параметре принимает только id сайта и с массивом не дружит, и ничего не отправляет
Здесь я так понмаю что нужно именно закачивать на сайт файл а потом прописывать пути типа "/readme.html" - а напрямую нельзя отправить файл на почту? без залива на сайт!
Разработчикам Битрикса думаю давно нужно было добавить функционал такого рода в систему. У каждого третьего клиента есть необходимость отправлять данные с аттачем. P.S. За класс огромное спасибо. Будем тестить
в D7 обработчик не будет работать! "Старыми", описанными методами - все ровно пашет, кроме момента определения CHARSET в b_lang - у меня почему-то пусто, хотя настройки сайтов выставлены...
Да и видимо добавили таки возможность слать аттачи
CEvent::Send("EVENT_NAME", SITE_ID, $arEventFields, "Y", "", array($file_id));
// где $file_id - это ID файла из таблицы b_file, файлов может быть несколько
Котов Алексей написал: Да и видимо добавили таки возможность слать аттачи
Не всегда работает, судя по всему, есть баг в ядре, если на кроне какое-то событие почтовое висит, а что-то выполняется на хитах, так как таблица эвентов может быть заблокирована и файлы не приаттачатся.
Можно не отправлять письмо дополнительно с помощью функции, а заполнить параметр $files. Письмо отправится стандартным способом и с вложениями.
function OnBeforeEventAddHandler(&$event, &$lid, &$arFields, &$messageId, &$files, &$languageId)
{
if ($event == "SALE_NEW_ORDER_YANDEX")
{
$files = Array("/readme_1.html","/readme_2.html");
// Вместо относительных путей можно указать ID
}
}
Недавно столкнулся со старой версией битрикса у клиента, нужно было реализовать нечто подобное Если в методе CEvent::Send id сайта передан как массив, то в методе SendAttach нужно поправить выборку при обращении к таблице b_event_message
Группы на сайте создаются не только сотрудниками «1С-Битрикс», но и партнерами компании. Поэтому мнения участников групп могут не совпадать с позицией компании «1С-Битрикс».