В двух предыдущих статьях мы настроили сервер и домен для дальнейшей отправки почты. Пришло время написать простую программу, которая и будет осуществлять рассылку. Поскольку реализуем мы все под веб-сервер, то писать скрипт будем на PHP.
Отправить письмо с сервера можно 3-я способами:
- через функцию mail() — самый простой и менее надежный вариант, его рассматривать не будем, кого интересует данный вид отправки, можете почитать в документации PHP;
- через SMTP-сервер, как собственный, так и сторонний — самый оптимальный вид отправки сообщений, его подробнее и рассмотрим в данной статье;
- через сторонние сервисы, такие как Amazon, Mandrill, Mailgun и прочее — хорошее и простое решения, но зачастую использование подобных серверов, может оказаться дороже собственного сервера. Подробнее рассмотрим в другой статье.
Для отправки письма через SMTP-сервер необходимо:
- данные для доступа к SMTP-серверу;
- e-mail получателя;
- письмо и его заголовок;
- системные заголовки.
С электронным адресом получателя, текстом письма и его заголовком, проблем нету. Данные для доступа мы имеем, обычно это хост, порт и пара логин/пароль. Остается составить системные заголовки, в них то и кроется вся сложность исходной задачи.
Создание системных заголовков
Рассмотрим основной набор заголовков, которое должно иметь письмо претендующее на попадание в папку «Входящие»:
Date: D, d M Y H:i:s UTС Subject: =?utf-8?B?base64_encode(subject)=?= Reply-To: name <email> MIME-Version: 1.0 Content-Type: text/html; charset="utf-8" Content-Transfer-Encoding: 8bit From: name <email> To: name <email> Message-ID: <message_id> Errors-To: email X-Complaints-To: email X-Sender: email List-Unsubscribe: <url/email> List-id: <list_id> Precedence: bulk
- Date — дата отправки;
- Subject — заголовок сообщения перекодированный в base64, чтобы избежать проблем с кодировкой;
- Reply-To — имя и e-mail для ответа;
- MIME-Version — версия MIME-стандарта;
- Content-Type — тип письма и его кодировка, тип письма обычно указывается html либо plain (текстовая версия);
- Content-Transfer-Encoding — тип конвертации, обычно используется «8bit»;
- From — имя и e-mail отправителя;
- To — имя и e-mail получателя;
- Message-ID — id сообщения в вашей системе;
- Errors-To — e-mail, куда будут отправлена информация о возникших ошибках;
- X-Complaints-To — e-mail, куда будут отправлена информация о возникших жалобах;
- X-Sender — e-mail системного отправителя;
- List-Unsubscribe — здесь указывается ссылка или e-mail для отписки;
- List-id — id текущей рассылки, для статистики;
- Precedence — этот заголовок необходим в случае массовой рассылки, значение ставится bulk.
Класс для отправки почты на PHP
С необходимыми заголовками разобрались, переходим теперь к написанию класса, который будет осуществлять отправку почты.
class MailSender { /* данные для подкючения */ private $default = array( 'smtp_host' => '127.0.0.1', 'smtp_port' => '25', 'smtp_login' => 'info@site.com', 'smtp_pass' => '1234567890', 'charset' => 'utf-8', 'from_name' => 'My name', 'from_email' => 'info@site.com', 'email_errors' => 'errors@site.com', ); /* функция отправки сообщений */ public static function send($email, $subject, $message, $unsub, $message_id = '', $list_id = '', $headers = '', $type = 'html') { $config = self::$default; /* проверка существования заголовков */ if(empty($headers)) { $headers = self::getHeaders($email, $subject, $type, $unsub, $message_id, $list_id); } /* добавление заголовков к сообщению */ $message = $headers . $message; /* создание сокета для подключения к SMTP-серверу */ if(!$socket = fsockopen($config['smtp_host'], $config['smtp_port'], $errno, $errstr, 30)) { echo $errno . "<br />" . $errstr; return false; } fputs($socket, "EHLO " . $config['smtp_host'] . "\r\n"); fputs($socket, "AUTH LOGIN\r\n"); fputs($socket, base64_encode($config['smtp_login']) . "\r\n"); fputs($socket, base64_encode($config['smtp_pass']) . "\r\n"); fputs($socket, "MAIL FROM: <" . $config['from_email'] . ">\r\n"); fputs($socket, "RCPT TO: <" . $email['email'] . ">\r\n"); fputs($socket, "DATA\r\n"); fputs($socket, $message . "\r\n.\r\n"); fputs($socket, "QUIT\r\n"); fclose($socket); return true; } /* функция генерации заголовков */ private static function getHeaders($email, $subject, $type, $unsub, $message_id, $list_id) { $config = self::$default; $result = ''; $result = "Date: ".date("D, d M Y H:i:s") . " UT\r\n"; $result .= "Subject: =?" . $config['charset'] . "?B?" . base64_encode($subject) . "=?=\r\n"; $result .= "Reply-To: " . $config['from_name'] . " <" . $config['from_email'] . ">\r\n"; $result .= "MIME-Version: 1.0\r\n"; $result .= "Content-Type: text/" . $type . "; charset=\"" . $config['charset'] . "\"\r\n"; $result .= "Content-Transfer-Encoding: 8bit\r\n"; $result .= "From: " . $config['from_name'] . " <" . $config['from_email'] . ">\r\n"; $result .= "To: " . $email['name'] . " <" . $email['email'] . ">\r\n"; $result .= "Errors-To: <" . $config['email_errors']. ">\r\n"; $result .= "X-Complaints-To: " . $config['email_errors'] . "\r\n"; $result .= "List-Unsubscribe: <{$unsub}>\r\n"; if(!empty($list_id)) $result .= "List-id: <" . $list_id . ">\r\n"; $result .= "Precedence: bulk\r\n"; return $result; } }
Отправка пробного письма
Для рассылки, почти, все готово, остается проверить, отправив пробное письмо.
require_once 'MailSender.php'; $email = array( 'email' => 'demo@site.com', 'name' => 'Имя', ); $subject = 'Тестовое письмо'; $message = '<p>Это текст тестового письма.</p>'; $unsub = 'https://site.com/'; MailSender::send($email, $subject, $message, $unsub);
Скачать готовый скрипт можно здесь.
На этом с отправкой почты заканчиваем, если возникли вопросы, задаем их в комментариях.