9
Мар

PHP: mail() через внешние SMTP msmtp

Ситуация следующая. У вас есть сервер за Cloudflare и вы не хотите светить его ip в заголовках письма. Или у вас хостер закрыл 25й порт, ну или сервер стоит дома и провайдер закрыл 25й порт. Вариантов множество.

Есть решение. Но как всегда с подводными камнями в настройке и работе.

Для начала устанавливаем на Centos

[bash title=»Centos»]yum install msmtp[/bash]

Или Ubuntu

[bash title=»Ubuntu»]apt-get install msmtp[/bash]

Говорят, нужно создать директорию

[bash title=»код»]~/ named .msmtprc[/bash]

Но я просто создал файл конфига на Ubuntu

[bash title=»код»]nano /etc/msmtprc[/bash]

[bash title=»код»]
defaults
tls on
tls_starttls on
tls_certcheck off
logfile /var/log/msmtp

account mail_yandex
host smtp.yandex.ru
port 25
auth on
user info@****.com.ua
password ************
from info@****.com.ua

account mail_server_2
host smtp.hd.zp.ua
port 25
auth on
user [email protected]
password *******
from [email protected]

account default : mail_server_2
[/bash]

Тут вы можете указать сразу несколько конфигов для подключения к почтовым серверам и использовать их как вам будет угодно в дальнейшем, о чём чуть дальше.
Обратите внимание, что по умолчанию мы указали 2й конфиг с названием mail_server_2

И так, сразу возможно возникнет проблема с тем, что msmtp не сможет писать лог.
Можно встретить примеры конфигов, где файл лога указывается как logfile /var/log/msmtp.txt
Но выдача прав на файл и вообще любые танцы с бубном ни к чему не привели. Поэтому используем без .txt

Если вдруг ничего не помогло:

[bash title=»код»]sudo touch /var/log/msmtp
sudo chown -R root:mail /var/log/msmtp
sudo chmod -R 660 /var/log/msmtp
sudo chown root:msmtp /etc/msmtprc
sudo chmod 640 /etc/msmtprc[/bash]

Дальше нужно установить симлинки

[bash title=»код»]ln -s /usr/bin/msmtp /usr/sbin/sendmail
ln -s /usr/bin/msmtp /usr/bin/sendmail
ln -s /usr/bin/msmtp /usr/lib/sendmail[/bash]

у меня ругалось что sendmail есть и пришлось его ликвидировать

[bash title=»код»]sudo rm /usr/sbin/sendmail[/bash]

После этого устанавливаем.

После этого необходимо подменить отправку в php.ini:

[bash title=»код»]sendmail_path = "/usr/bin/msmtp -t"[/bash]

Для виртуальныж хостов вызываем нужную нам секцию отправки:

[bash title=»код»]php_admin_value sendmail_path "/usr/bin/msmtp -a mail_yandex -t"[/bash]

Тут вы указываете какой конфиг использовать для отправки почты. Ведь у вас может быть много сайтов на сервере и много разных ящиков для отправки почты.

Для VestaCP или Hestia нужно указать почту в секции nano /home/пользователь/conf/web/хост/apache2.ssl.conf

[bash title=»код»]
<Directory /home/caca/web/hd.zp.ua/public_html>
AllowOverride All
SSLRequireSSL
Options +Includes -Indexes +ExecCGI
php_admin_value sendmail_path "/usr/bin/msmtp -a mail_yandex -t"
</Directory>
[/bash]

И перегружаем Apache:

[bash title=»код»]sudo service apache2 restart[/bash]

Вроде бы и всё, но нет.
Можно протестировать почту из консоли

[bash title=»код»]echo "Test message." | msmtp -a mail_yandex [email protected][/bash]

Почта должна уйти.
Если уже прописали в виртуальные хосты, то также должна уходить, но есть два момента:
1. Почта не уходит. Возможно, php.ini для консоли и для виртуального хоста используется разный. Проверьте.
2. Почта с сайта уходит очень долго и поэтому всё жутко тупит до отправки. Ведь php скрипт ждёт true в ответ на отправку почты и всё это время сайт для вас висит.

Решение костыльное, но есть. Но увы, нужны минимальные знания php и вашего скрипта.
Нужно либо добавить в скрипт асинхронную отправку почты, либо вместо отправки из скрипта, сделать скрипт добавления писем в базу данных Mysql и раз в 1-5 минут по cron делать отправку.

Создаём таблицу MySQL

[bash title=»код»]
CREATE TABLE messages (
id INT AUTO_INCREMENT PRIMARY KEY,
to_email VARCHAR(255) NOT NULL,
from_email VARCHAR(255) NOT NULL,
subject VARCHAR(255) NOT NULL,
message TEXT NOT NULL,
mail_headers TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
[/bash]

Для примера, форум SMF
Файл Subs-Post.php

Вместо

[php title=»php код»]
if (!mail(strtr($to, array("\r" => », "\n" => »)), $subject, $message, $headers, sprintf("-oi -f %s", $webmaster_email)))
{
log_error(sprintf($txt[‘mail_send_unable’], $to));
$mail_result = false;
}
[/php]

[php title=»php код»]
$to = strtr($to, array("\r" => », "\n" => »));
$smcFunc[‘db_insert’](»,
‘messages’, // Название таблицы для логирования
array(
‘subject’ => ‘string’,
‘message’ => ‘string’,
‘mail_headers’ => ‘string’,
‘from_email’ => ‘string’,
‘to_email’ => ‘string’,
),
array(
‘subject’ => $subject,
‘message’ => $message,
‘mail_headers’ => $headers,
‘from_email’ => $webmaster_email,
‘to_email’ => $to,
),
array(‘id’)
);
[/php]

для DLE
в файле mail.class.php
Вместо

[php title=»php код»]
if( !@mail( $this->to, $this->subject, $this->message, $this->mail_headers, $this->additional_parameters ) ) {
if( !@mail( $this->to, $this->subject, $this->message, $this->mail_headers) ) {
$this->smtp_msg = "PHP Mail Error.";
$this->send_error = true;
}
}
[/php]

[php title=»php код»]
$to = $db->safesql($to);
$from = $db->safesql($this->from);
$subject = $db->safesql($subject);
$message = $db->safesql($this->message);
$mail_headers = $db->safesql($this->mail_headers);
$query = "INSERT INTO messages (to_email, from_email, subject, message, mail_headers) VALUES (‘$to’, ‘$from’, ‘$subject’, ‘$message’, ‘$mail_headers’)";
$db->query($query);
[/php]

В итоге у нас будут заносится наши письма с нужными заголовками в базу данных. Теперь нужно создать скрипт отправки по cron

send_mes.php

[php title=»php код»]
<?php
// Подключение к базе данных
$mysqli = new mysqli(‘localhost’, ‘пользователь’, ‘пароль’, ‘ваша_база_данных’);

// Проверка соединения
if ($mysqli->connect_errno) {
echo "Не удалось подключиться к MySQL: " . $mysqli->connect_error;
exit();
}

// Получение сообщений из очереди
$query = "SELECT * FROM messages";
$result = $mysqli->query($query);

$idsToDelete = array(); // Массив для хранения идентификаторов записей, которые нужно удалить

if ($result->num_rows > 0) {
// Отправка сообщений
while ($row = $result->fetch_assoc()) {
$to = $row[‘to_email’];
$subject = $row[‘subject’];
$message = $row[‘message’];
$mail_headers = $row[‘mail_headers’];
$id = $row[‘id’];

// Отправка письма
if (mail($to, $subject, $message, $mail_headers)) {
// Добавляем идентификатор записи в массив для удаления
$idsToDelete[] = $id;
echo "Отправлено $to.";
} else {
echo "Ошибка при отправке сообщения на адрес $to.";
}
}
} else {
echo "Нет сообщений в очереди.";
}

// Удаление записей после завершения цикла
if (!empty($idsToDelete)) {
$idsString = implode(‘,’, $idsToDelete);
$deleteQuery = "DELETE FROM messages WHERE id IN ($idsString)";
if ($mysqli->query($deleteQuery)) {
echo "Удалено записей из базы данных: " . count($idsToDelete);
} else {
echo "Ошибка при удалении записей из базы данных: " . $mysqli->error;
}
}

// Закрываем соединение
$mysqli->close();
[/php]

Обратная связь

    The average number of adverse effects was 3. T max is 23 minutes in females and 32 minutes in males. What other drugs will affect doxercalciferol Viagra natural sin receta. Archived from the original on 2009-08-14.

    Talk to your doctor before using this form of cefadroxil if you have diabetes. What should I tell my healthcare team before starting CABLIVI? There is no FDA guidance on the use of Tetracycline (oral) with respect to specific gender populations https://www.apotheke-rezeptfreie.com/. Opper K, Uder S, Song K Development of Heterogeneous and Homogeneous Platforms for Rapid Analysis of DNA-Protein Interactions.

    Contact Us