Почтовая программа. Отправка почты на PHP

В двух предыдущих статьях мы настроили сервер и домен для дальнейшей отправки почты. Пришло время написать простую программу, которая и будет осуществлять рассылку. Поскольку реализуем мы все под веб-сервер, то писать скрипт будем на PHP.

Отправить письмо с сервера можно 3-я способами:

  • через функцию mail() – самый простой и менее надежный вариант, его рассматривать не будем, кого интересует данный вид отправки, можете почитать в документации PHP;
  • через SMTP-сервер, как собственный, так и сторонний – самый оптимальный вид отправки сообщений, его подробнее и рассмотрим в данной статье;
  • через сторонние сервисы, такие как AmazonMandrill, 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);

Скачать готовый скрипт можно здесь.

На этом с отправкой почты заканчиваем, если возникли вопросы, задаем их в комментариях.

Также может быть интересно: