В Битриксе, начиная с версии 7.1.3, появилась возможность переопределить стандартный механизм отправки почты.
Когда может быть полезен такой финт ушами? К примеру, когда в конторе есть какой-то централизованный сервис отправки почты, который должны использовать все приложения (SMTP-сервер на другой машине, веб-служба, что угодно). Для примера, рассмотрим GMail в качестве такого сервиса.[spoiler]
Механика простая: везде, где должна вызываться функция mail(), вызывается bxmail(). А уже в этой функции, перед вызовом стандартной функции mail(), Битрикс проверяет, определена ли функция custom_mail() и, если да, вызывает её вместо mail(). Соответственно, чтобы переопределить механизм отправки, нужно всего лишь написать функцию custom_mail() (в /bitrix/php_interface/init.php, к примеру (если хотим, чтобы такой механизм отправки действовал для всех сайтов на данной копии)).
Приступим к делу! Лично мне для отправки почты через GMail ближе всего Zend_Mail, но... Ни эта библиотека, ни другие не позволяют установить "сырые" заголовки для письма. А разбирать $additional_headers мне что-то не очень хочется. Следовательно, выбор перепадает на PEAR::Net_SMTP, как на механизм прямой работы с SMTP-сервером.
Итак, ближе к коду!
require_once 'Net/SMTP.php';
/**
* Отпраляем почту через SMTP-сервер GMail (пользователь: user@gmail.com).
*
* @see CEvent::HandleEvent()
* @see bxmail()
*
* @param string $to Адрес получателя.
* @param string $subject Тема.
* @param string $message Текст сообщения.
* @param string $additionalHeaders Дополнительные заголовки передаются Битриксом почти всегда ("FROM" передаётся здесь).
*
* @return bool
*/
function custom_mail($to, $subject, $message, $additionalHeaders = '')
{
/*
* Настройки можно (нужно) вынести в админку, но это уже домашнее задание :)
*/
$smtpServerHost = 'ssl://smtp.gmail.com';
$smtpServerHostPort = 465;
$smtpServerUser = 'user@gmail.com';
$smtpServerUserPassword = 'password';
if (!($smtp = new Net_SMTP($smtpServerHost, $smtpServerHostPort))) {
return false;
}
if (PEAR::isError($e = $smtp->connect())) {
return false;
}
if (PEAR::isError($e = $smtp->auth($smtpServerUser, $smtpServerUserPassword))) {
return false;
}
preg_match('/From: (.+)\n/i', $additionalHeaders, $matches);
list(, $from) = $matches;
$smtp->mailFrom($from);
$smtp->rcptTo($to);
/*
* Получаем идентификатор конца строки у Битрикса.
*/
$eol = CAllEvent::GetMailEOL();
$additionalHeaders .= $eol . 'Subject: ' . $subject;
if (PEAR::isError($e = $smtp->data($additionalHeaders . "\r\n\r\n" . $message))) {
return false;
}
$smtp->disconnect();
return true;
}
Вынесение настроек в админку, создание статического объекта соединения (чтобы не тратить время при отправке множества писем за раз) — это всё задания на дом
Ветров Михаил, согласен, рынок для такого расширения всё ещё есть. Видимо, это только я уже давно не вижу «обычных» shared-хостингов и поэтому на них не ориентируюсь (и не хочу, т.к. не вижу будущего у shared-хостинга).
По поводу одного ящика — не совсем так. В случае GMail — может быть любой адрес, подтверждённый в настройках аккаунта. Но лучше использовать специальный сервис для отправки (типа SendGrid, Postmark или Mandrill), через который будет отправляться почта, — в этом случае адрес отправителя может быть любым.
P.S. Вариант с GMail в статье идёт только в качестве примера. Я привёл выше сервисы, которые реально подходят для этогой задачи.
Разместил файл с скриптом в указанном месте. И теперь при заходе на сайт появляется вот такая ерунда (Screenshot_1) Версия КП 15.5.1 Права на файл выставил такие же, как и на файлы в папке. Если этот скрипт запустить в "Командная PHP-строка", то отрабатывает без ошибок. Подскажите в какую сторону капать?
Степаненко Александр, Вы, видимо, забыли открывающий PHP-тег в начале файла(<?php). Я опустил его в статье, т.к. в файле может быть не только этот код, но и другой.
В любом случае, вам так же нужно будет установить библиотеку Net_SMTP для PEAR. Это код служит примером для разработчиков, я не проверял этот код с момента его написания, поэтому его работоспособность однозначно не гарантирую
Так же, этот вопрос лучше решить не доработкой Битрикса, а модификацией настроек почтовой программы на сервере (Exim, Postfix) — это надёжнее. За подробностями можете написать мне в личку.
Небольшое замечание, для phpmailer, что бы он кушал ваши вложения и не давился, требуется указать что-то такое (задать разделитель для этих ваших вложений, ну и да, напишите что-то более крутое, чем эти substr - не путь самурая, совсем не он...):
Мурад Алиев, всё правильно. Но способ довольно мудрёный, в том плане, что отладка нетривиальна.
Поэтому, если у Вас что-то не отправляется, то пишите логи из функции, смотрите на ошибки...
А вообще, как я уже писал выше, намного лучше доверить эту задачу почтовому серверу (Postfix или Exim). Просто настройте их на использование вашего аккаунта в Gmail/Sendgrid/...
Алексей Шоков, всплывает такая проблема. У меня при событии отправки почты я отправляю еще одно письмо о подтверждении. Так вот письмо приходит только то письмо что прикреплено в событии. Если закомментировать метод то приходят оба письма.
На счет настройки "почтовому серверу (Postfix или Exim)." я попытаюсь настроить. только вот не всплывет ли подобна ошибка?
А подскажите пожалуйста как можно заменить заголовок приходящих писем т.е сейчас подставляется email указанный в настройках, можно ли заменить на типа название сайта как это сделано вот тут - http://prntscr.com/asj6xg
потом в функции custom_mail формируем отправку письма не по параметрам этой функции, а по полям из глобальной переменной, заменяя их по вкусу и добавляя дополнительные
Дмитрий Козлов, спасибо большое. но это не совсем то. В письме что приходят с сайта подставляется email что указывали в $smtpServerUser = 'user@gmail.com'; Как сделать запись как вот тут - http://prntscr.com/b4i2eo
Руслан Хаитов, делать рассылку через почту Яндекса лучше не стоит. GMail, Яндекс — это всё сервисы для личной почты. Иногда через них можно отправлять транзакционные письма (информация о заказе, ответ на сообщение на форуме,..), но не массовые рассылки.
Во-первых, все эти сервисы имею органичение на количество писем в час/день.
Во-вторых, за такую активность достаточно бысто забанят.
Используйте специализированные сервисы типа MailChimp или SendGrid.
А если у нас рассылка до 5000 пользователей 4 раза в месяц край. Стоит в этом случае использовать Gmail или все же попробовать через вышеупомянутые сервисы рассылать? Заранее спасибо за ответ?
Руслан Хаитов, стоит использовать правильный вариант (MailChimp, SendGrid). Тем более, что установка там такая же по сложности + бесплатные тарифы даже есть.
Майоров Федор, некоторое время пытался вкурить, в чем же фишка этой магической строки. Пока не дошло, что для phpMailer надо продублировать заголовки из $additional_headers. У меня в итоге вот такой вариант получился. Корректно шлет html и текст, с аттачами и без них. https://gist.github.com/igorbarkowsky/...833838fea5
function custom_mail ($to, $subject, $message, $additional_headers, $additional_parameters)
{
/*\AddMessage2Log(
'To: '.$to.PHP_EOL.
'Subject: '.$subject.PHP_EOL.
'Message: '.$message.PHP_EOL.
'Headers: '.$additional_headers.PHP_EOL.
'Params: '.$additional_parameters.PHP_EOL
);*/
require_once $_SERVER['DOCUMENT_ROOT'].'/vendor/autoload.php';
$to = str_replace(' ','',$to);
$mail = new PHPMailer;
$mail->CharSet = 'UTF-8';
$address = explode(',', $to);
foreach ($address as $addr)
$mail->addAddress($addr);
// Просматриваем заголовки на предмет аттачей
$headers = explode("\n", $additional_headers);
// Определить аттачи легко - передается сепаратор таким вот образом
$attachHeader = 'Content-Type: multipart/mixed; boundary=';
foreach( $headers as $h )
{
// Если есть заголовок с ограничиителем
if( stripos($h, $attachHeader) === 0 )
{
// Вытаскиваем значение сепаратора
$bndr = substr($h, strlen($attachHeader));
$bndr = trim($bndr, '"');
// И дублируем его же, но в свойство phpMailer.
$mail->ContentType = 'multipart/mixed; boundary="' . $bndr . '"';
// I know its dirty hack
break;
}
}
if (substr_count($message, "Content-Type: text/html"))
{
// $mail->Encoding = '8bit';
}
else
{
// $mail->Encoding = '8bit';
//$mail->isHTML(true); // Set email format to HTML
}
$mail->Subject = $subject;
$mail->Body = $message;
if( defined('PROJECT_SMTP_HOST') )
{
$mail->IsSMTP();
$mail->SMTPDebug = defined('PROJECT_SMTP_DEBUG_LEVEL') ? PROJECT_SMTP_DEBUG_LEVEL : 0;
$mail->Host = PROJECT_SMTP_HOST;
$mail->SMTPAuth = true; // enable SMTP authentication
$mail->Username = PROJECT_SMTP_USERNAME;
$mail->Password = PROJECT_SMTP_PASSWORD;
$mail->From = PROJECT_SMTP_FROM;
$mail->FromName = PROJECT_SMTP_FROMNAME;
$mail->SMTPSecure = PROJECT_SMTP_SECURITY; // "tls" or "ssl"
$mail->Port = PROJECT_SMTP_PORT;
//HACK: Dirty hack! if ssl not configured at hosting
$mail->SMTPOptions = array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
),
);
}
if( !$mail->send() )
{
\AddMessage2Log('Mailer Error: ' . $mail->ErrorInfo);
return false;
}
return true;
}
Чуев Василий, нет особой разницы, с помощью чего вы шлете почту со своего сервера. В спам оно попадает, потому что гмайл видит, что вы отправили почту не с сервера с доменным именем вашего сайта. А с некоего технического домена. Тут вам надо бороться именно с гмайлом:) И в первую очередь, конечно надо добавить для домена вашего сайта spf-записи, типа таких
В этом случае почтовый сервер яндекса, который по факту и занимается доставкой вашей почты на адреса реципиентов, начнет воспринимать ваш сервер как доверенный и будет помечать в заголовке письма, что оно отправлено с разрешенного сервера.
Ну а если эта запись не поможет против гмайла, то есть еще такой рецепт:
v=spf1 ip4:тут.айпи.вашего.сайта a mx include:_spf.google.com ~all
К слову сказать, у вас в настройках яндекс.почты опечатка
Добрый день. Запутался маленько, получается с помощью данного механизма можно разделить почту по типам. В стиле информация о задачах с 1 почты, информация о событиях календаря с другой?
Добрый день. В чем суть проблемы: Битрикс умеет отправляет почту через php функцию mail(), которая в свою очередь использует настройку PHP sendmail_path.
Можно задать отправку через консольный клиент msmtp, либо через локальный smtp сервер (postfix, exim, sendmail и так далее). Мы будем отправлять через msmtp, настроенный на отправку через Яндекс Почту.
При отправке писем Битрикс формирует почтовые заголовки, в частности From, исходя из настроек в админке, в главном модуле. При этом имя пользователя при авторизации на почтовом сервере и в заголовке From должно совпадать. При одном сайте/одном домене проблем нет. При нескольких отдельных сайтах/доменах тоже проблем нет.
В конфиге msmtp прописывается почтовый аккаунт для каждого сайта и в админке соответствующего сайта можно указать какой аккаунт из конфига использовать.
Но несколько сайтов/доменов, работающих на многосайтовости, то есть общем ядре и значит админке, не позволяют использовать такой способ.
Единственный вариант, который я нашел, это использовать возможность Битрикса по переопределению функции отправки почты и создания custom_mail(), которая в зависимости от сайта/домена будет подставлять соответствющий аккаунт при вызове msmtp.
Зарипов Данис, да, работает, настроил отправку почты через Яндекс по данной инструкции.
Есть другая проблема: при отправке почты сразу нескольким получателям почта уходит только на первый указанный адрес, именно на первый, а не на какой-то особенный из списка. Отправляем на "test1@test.ru,test2@test.ru" - придет только на test1, отправляем на "test2@test.ru,test1@test.ru" - придет только на test2. В Яндекс уже обращался, они не видят проблем на своей стороне, может быть кто-то знает с чем это может быть связано?
Постников Алексей, "В конфиге msmtp прописывается почтовый аккаунт для каждого сайта и в админке соответствующего сайта можно указать какой аккаунт из конфига использовать." Помогите разобраться. Коробочная версия CRM "1С-Битрикс24: Корпоративный портал 250". CRM сайт - s1. Все работает. Уведомления отправляются от email админа (adminS1crm@yandex.ru). После добавления второго сайта - s2 и изменения почты E-Mail отдела продаж в "Рабочий стол - Настройки - Настройки продукта - Настройки модулей" на свой (otdelProdazhS2@yandex.ru) вместо email админа (adminS1crm@yandex.ru), перестали приходить уведомления о заказах на сайте S2. Можно это решить прописав в конфиге msmtp аккаунт для сайта - s2. Сейчас прописано для сайта Default. В консоли настройки BitrixVM отображается только один сайт.
Можно ли это использовать, чтобы отправлять почту не через один ящик как сейчас, а напрямую? Наверное, надо как-то определить ящик отправитель и подставить соответствующие ему параметры авторизации $smtpServerUser = 'user@gmail.com'; $smtpServerUserPassword = 'password'; Правильно?
Группы на сайте создаются не только сотрудниками «1С-Битрикс», но и партнерами компании. Поэтому мнения участников групп могут не совпадать с позицией компании «1С-Битрикс».