Новая версия класса SendMailSmtpClass. Отправка файлов через smtp с авторизацией по протоколу SSL на php

Новая версия класса SendMailSmtpClass

Больше четырех лет назад, я написал для своих нужд небольшой класс, для отправки писем через smtp. Это была первая версия SendMailSmtpClass. Через несколько месяцев после публикации класса и статьи о нем, на блоге прилично увеличилась посещаемость, и почти все поисковые запросы, так или иначе, были на тему отправки писем через smtp. Спустя еще 8-9 месяцев я немного дописал класс, теперь он смог отправлять письме через smtp с возможностью авторизации по ssl. Продолжение темы также стало быстро популярно среди посетителей сайта. И даже спустя 4 года темя не теряет своей актуальности, о чем может свидетельствовать десятки комментарием под статьями. А также, если верить метрике, то за последний месяц эти две статьи прочитало больше двух тысяч человек.
Выходит, что тема нужная и популярность ее не угасает. Но, судя по комментариям и письмам с вопросами, которые мне приходят на почту, то класс имеет свои недостатки. Самым большим, из которых является не удобная отправка файлов. Поэтому я решил немного обновить класс SendMailSmtpClass и добавить в него несколько улучшений.

Обновленный класс SendMailSmtpClass. Версия 1.1

Для тех, кому лень или некогда читать всю статью, сразу выкладываю ссылку на обновленный класс, он теперь хранится на github: репозиторий. А также скачать можно архивом: скачать.

Небольшие, но полезные обновления в SendMailSmtpClass

В первую очередь была немного переделана сама отправка письма, а именно приветственный запрос к smtp-серверам. Некоторые сервера не всегда отвечают на команду HELO, поэтому теперь в приветствии сначала отправляется EHLO. Если на EHLO нет ответа, то уже только тогда происходит отправка HELO. Надеюсь, эти манипуляции уменьшат процент проблем с авторизацией на smtp серверах.
Вторая переделка упростила код вызова класса и отправки письма. Теперь не нужно самим описывать заголовки – это происходит автоматически.
Третье обновление, это возможность отправки письма сразу нескольким получателям. Для этого достаточно указать получателей через запятую.
Ниже приведен код обновленной отправки с помощью smtp яндекса:

require_once "SendMailSmtpClass.php"; // подключаем класс
$mailSMTP = new SendMailSmtpClass('zhenikipatov@yandex.ru', '***', 'ssl://smtp.yandex.ru', 465, "UTF-8");
// $mailSMTP = new SendMailSmtpClass('логин', 'пароль', 'хост', 'порт', 'кодировка письма');

// от кого
$from = array(
	"Евгений", // Имя отправителя
	"test@vk-book.ru" // почта отправителя
);
// кому
$to = 'admin@vk-book.ru, ipatov@mega-dev.ru';

// отправляем письмо
$result =  $mailSMTP->send($to, 'Тема письма', 'Текст письма', $from); 
// $result =  $mailSMTP->send('Кому письмо', 'Тема письма', 'Текст письма', 'Отправитель письма');

if($result === true){
	echo "Done";
}else{
	echo "Error: " . $result;
}

Отправка писем в разной кодировке с помощью SendMailSmtpClass

Еще одно обновление класса – это возможность отправлять письма в разных кодировках. На данный момент можно использовать кодировки utf-8 и windows-1251. Это две самые популярные кодировки текста, с другими я не сталкивался при отправках почты. Если кому-то необходимы еще какие-то варианты кодировок, то пишите в комментарии, я постараюсь добавить их поддержку.
Для установки типа кодировки письма достаточно при инициализации класса указать нужную:

// будет использована кодировка utf-8
$mailSMTP = new SendMailSmtpClass('zhenikipatov@yandex.ru', '***', 'ssl://smtp.yandex.ru', 465, "UTF-8"); 

Отправка файлов через smtp с помощью SendMailSmtpClass

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

// добавляем файлы
$mailSMTP->addFile("test.jpg");
$mailSMTP->addFile("test2.jpg");
$mailSMTP->addFile("test3.txt");

Код класса и пример использования можно скачать из репозитория на github: ссылка.

Послесловие

Пишите свои комментарии по работе новой версии класса. Если есть какие-то пожелания или идеи, то также пишите о них.
Возможно, года через 4, выйдет новая версия класса :)


Рассказать друзьям:


Оценить:
(12 оценок, среднее: 4,92 из 5)

Новая версия класса SendMailSmtpClass. Отправка файлов через smtp с авторизацией по протоколу SSL на php: 68 комментариев

  1. Hi there would you mind letting me know which webhost you’re using?
    I’ve loaded your blog in 3 completely different
    web browsers and I must say this blog loads a lot quicker then most.
    Can you recommend a good web hosting provider at a
    reasonable price? Many thanks, I appreciate it!

      1. «И даже спустя 4 года темЯ не теряет своей актуальности,» Очепятку исправьте.

  2. Приветствую, а письма в «отправленных» на сервере сохраняются?
    И можно ли в скрытую копию адрес вставлять?

    1. Добрый день!
      Нет, в отправленных письма не сохраняются.
      Скрытую копию и просто копию добавлять нельзя — не было необходимости и как-то не подумал об этом. Когда доберусь до обновления класса, то обязательно добавлю этот функционал. Спасибо за идею!
      Если у кого-то еще есть идеи и предложения по улучшению и расширению функционала, то пиши — постараюсь все учесть и внести доработки в ближайшее время.

      1. Спасибо Вам.
        Попробую в файле класса «Bcc:» к заголовкам добавить, чтобы можно было скрытую копию указать.
        Через почтовую программу письма получаю, пишет To: undisclosed-recipients
        Видимо в заголовках «Кому» не прописано». Не на что не влияет, просто заметил особенность.

  3. $headers.= «To: «.$mailTo.»\r\n»;

    выдает ошибку:

    Notice: Undefined variable: mailTo in /…/SendMailSmtpClass/SendMailSmtpClass.php on line 200

    1. Это потому, что внутри метода getContentMail, не существует переменная $mailTo. Ее туда нужно передать сначала

        1. На блог заходят программисты разного уровня :) Для многих ООП или даже просто область видимости переменных — это сложно

  4. Добрый день!
    Спасибо за класс! Очень полезная штука.
    У меня есть проблемка с вложением файла. К письму при отправке прикрепляю файл jpg, а он приходит как текстовый, хотя расширение остается правильным. И в web интерфейсе ящика вложение не открывается…

    Какие могут быть причины такого поведения?

    1. Добрый день!
      Проверьте, как прикрепляете файл и существование самого файла. Если не получается, покажите код — только в комментарии его нужно обрамлять тегами pre, чтобы спецсимволы не порезались :)

    1. Приветствую! Для mail.ru критично, чтобы отправитель был указан тот же самый почтовый ящик, с которого происходит подключение по smtp, иначе не хочет слать.
      С яндексом проще — он шлет письмо с любым почтовым адресом отправителя, кроме mail.ru
      Проверьте, чтобы вот тут были указаны верные данные:

      // от кого
      $from = array(
          "Имя", // Имя отправителя
          "test@vk-book.ru" // почта отправителя. Для mail.ru нужно указать тот же ящик, что и в логине при инициализации класса. А для яндекса любой, кроме mail.ru
      );
      
      1. Да, все получилось. Спасибо. Через mail проверил по рекомендациям — работает. Но неинтересно в таком раскладе. Через yandex шлю на mail. Единственно,что не комильфо: в веб почте на mail.ru получаю такое: To: undisclosed-recipients (уже писали люди выше).

        1. Пояс на GMT+004 настроен) Хотя у меня время Московское. Честно говоря, я даже не обращал внимание 5 лет, пока Вы не сказали)

  5. Здравствуйте! Спасибо за Вашу программу.

    У меня не отправляется ничего, выдается ошибка:
    Error: .
    Добавил echo внутри класса:
    if(!$socket = @fsockopen($this->smtp_host, $this->smtp_port, $errorNumber, $errorDescription, 30)){
    echo $errorNumber.».».$errorDescription;
    throw new Exception($errorNumber.».».$errorDescription);
    }
    стала выходить ошибка
    Error: Autorization error

    Я правильно понимаю, что на smtp сервисе нужно завести почтовый ящик, и при подключении класса указывать его адрес и пароль? На ящик захожу с паролем без проблем, а вот попытка с тем же паролем отправить письмо через класс выходит ошибка.

    require_once «SendMailSmtpClass.php»;
    $mailSMTP = new SendMailSmtpClass(‘box1@mail.ru’, ‘12345’, ‘ssl://smtp.mail.ru’, 465, «UTF-8»);

    $from = array(
    «Alex»,
    «box1@mail.ru»
    );
    $to = ‘box2@ya.ru’;

    $result = $mailSMTP->send($to, ‘Тема письма’, ‘Текст письма’, $from);

  6. Сменил сервис mail.ru на yandex.ru и все заработало. На mail.ru нужно привязывать почтовый ящик к домену, а потом еще прописывать настройки MX-записи у своего провайдера, но я не стал заморачиваться. И да, с яндекса на майл не отправляется, печалька.

  7. Добрый день, у меня одна и та же ошибка — ошибка авторизации когда подключаюсь ко гугл почте, Error of command sending: RCPT TO нашел строки в коде класса, но ничего не понял( помогитее

    1. Добрый день!
      Покажите код отправки и на какие ящики пытаетесь отправить письмо. А то так не понятно в чем дело. Такая ошибка появляется если сервер не может понять кому слать или отправить письмо адресату

      1. require_once "scripts/SendMailSmtpClass.php";
        
        $mailSMTP = new SendMailSmtpClass('vitalik.shumanskyi@gmail.com', 'xxx', 'ssl://smtp.gmail.com', 465, "utf-8");
        
        $from = array(
        	"Shumik_UA", // Имя отправителя
        	"vitalik.shumanskyi@gmail.com" // почта отправителя
        );
        
        $to = "$login";
        
        $result =  $mailSMTP->send($to, 'Підтвердження реєстрації', 'перейдіть по цій силці для того щоб підтвердити реєстрацію', $from); 
        
        if($result === true){
        	echo "Done";
        }else{
        	echo "Error: " . $result;
        }
        
        1. Попробуйте вместо переменной $to подставить какой-нибудь ящик для теста. И проверьте какие данные туда подставляются. В $login хранится почтовый ящик? не обязательно переменную оборачивать кавычками тут: $to = «$login»;

          1. ооо позор на мою голову) я вместо переменной $email поставил $login) огроомное спасибо) протестил что отправляю — сразу все понял, подставил емайл и все пошло)) еще раз спасибо за быструю поддержку и ваш способ отправки!)

  8. Добрый день! А что делать, если нет авторизации на сервере.
    К примеру, на работе сервер nsmail.work.ru без авторизации по 25 порту.
    Указываю $mailSMTP = new SendMailSmtpClass(«»,»», ‘nsmail.obespechenie-vniief.ru’, 25, «UTF-8»);
    Пишет: Ошибка: Autorization error
    Если в самом классе прописать public function __construct($smtp_username = «», $smtp_password = «», $smtp_host, $smtp_port = 25, $smtp_charset = «utf-8») — та же ошибка.
    Но если закомментировать строки авторизации
    fputs($socket, «AUTH LOGIN\r\n»);
    if (!$this->_parseServer($socket, «334»)) {
    fclose($socket);
    throw new Exception(‘Autorization error’);
    }

    fputs($socket, base64_encode($this->smtp_username) . «\r\n»);
    if (!$this->_parseServer($socket, «334»)) {
    fclose($socket);
    throw new Exception(‘Autorization error’);
    }

    fputs($socket, base64_encode($this->smtp_password) . «\r\n»);
    if (!$this->_parseServer($socket, «235»)) {
    fclose($socket);
    throw new Exception(‘Autorization error’);
    }
    То письмо отправляется. Я корректно настроила?

    1. Добрый день! Да, Вы все верно исправили в коде класса. В нем нет проверки на сервера без авторизации. И код, что Вы убрали, как раз и отвечает за обмен с smtp данными для авторизации — получается, что они на Вашем сервере не нужны

  9. Добрый день! Пытаюсь заставить работать у себя. Выдаёт «Письмо не отправлено. Ошибка: .»
    Код:
    require_once "SendMailSmtpClass.php";

    $mailSMTP = new SendMailSmtpClass('aveteamsup@gmail.com', '*****', 'ssl://smtp.gmail.com', 'Ave Team', 465, "UTF_8");
    $headers= "Закінчить реєстрацію\r\n";
    $headers .= "Content-type: text/html; charset=utf-8\r\n"; // кодировка письма
    $headers .= "From: Ave Team \r\n"; // от кого письмо*/
    $from = array(
    "Ave Team", // Имя отправителя
    "aveteamsup@gmail.com" // почта отправителя
    );
    $to=$mail;
    $result = $mailSMTP->send($to, 'Реєстрація', 'Текст письма', $from);
    if($result === true){
    echo "Письмо успешно отправлено";
    }else{
    echo "Письмо не отправлено. Ошибка: " . $result;
    }

    Где может быть ошибка?

    1. Добрый день!
      Попробуйте при инициализации класса, в последнем параметре вместо «UTF_8» написать «UTF-8», возможно из-за кодировки письмо не принимается smtp-сервером

  10. По какой причине на одном хостинге скрипт может работать, а на другом нет (error: 0)?

    1. Нужно подебажить, посмотреть, в каком месте происходит ошибка. Проверьте правильно ли подставляется SERVER_NAME в методе приветствия

  11. Огромное спасибо!
    Опыт в php пока не большой, два дня искал решение по отправке писем с localhost из php (MAMP), тк стандартная функция mail() не работает в такой конфигурации. Находил либо тяжелые, либо не рабочие решения, либо заглушки с сохранением в файл.
    Но Ваше решение подошло идеально!

  12. Здравствуйте,
    У меня немного нетипичная задача. Мне нужно отправлять e-mail периодически запуская скрипт Task Scheduler’ом в Windows 7. Попробовал использовать ваш класс. При запуске скрипта шедулером выходит сообщение
    «Php notice: Undefined index: SERVER_NAME in f:\server\путь к файлу\SendMailSmtpClass.php on line 77»
    Error: Error of command sending: HELO
    Скриншот: https://prnt.sc/kav90s

    Но если дергать скрипт из броузера под локальным апачем, то все отрабатывает замечательно (письма уходят, ошибок нет).

    1. Проблема в том, что винда не может определить SERVER_NAME. Undefined index: SERVER_NAME Можно попробовать в классе подправить — просто руками там прописать хост: localhost или 127.0.0.1.

  13. Добрый день, подскажите как увеличить timeout? А то при большом количестве адресов приходит назад с ошибкой timeout.

    1. Добрый день! SMTP-сервер возвращает timeout или на ваш скрипт на сервере? Если smtp вернуло, то можно разбить отправку на части. А если на вашем сервере, то это настраивается в apache и php.ini. Также можно из самого скрипта с помощью set_time_limit

  14. Прекрасная идея проекта. Мне все нравится, но будет ли реализовано сохранение писем в отправленные? Очень полезная фича была бы.

    1. Здравствуйте! В этом года нет толком времени заниматься блогом и скриптом smtp в частности( Сейчас собираю все по комментам и письмам, что мне присылали по smtp. Постараюсь на новогодних каникулах внести правки и доработки в скрипт

  15. Не знаком с github’ом, но постарался предложить там исправление в классе.
    Предлагаю
    $contentMail = «Date: » . date(«D, d M Y H:i:s») . » UT\r\n»;
    заменить на
    $contentMail = «Date: » . gmdate(«D, d M Y H:i:s») . » UT\r\n»;

    Иначе получатель видит письма из будущего (к часовому поясу сервера плюсуется часовой пояс получателя).

  16. Евгений! Спасибо за скрипт, много лет работал. Но вот недавно перестал работать с mail.ru Что делать? Просто не отправляет. Тестовый скрипт выдает Error: E-mail didn’t sent

    1. Добрый день! С ходу не могу ответить, давно не работал с mail.ru. Надо разбираться, постараюсь на выходных посмотреть.
      Проверьте логин и пароль, возможно mail.ru просто заблочили аккаунт, такое бывает у smtp. И проверьте, чтобы отправитель и логин smtp были одинаковые — это обязательное правило для mail.ru

  17. С яндексом какая-то муть. Для новых аккаунтов выдает ошибку Autorization error, со старыми акками нормально работает. Что может быть?

  18. Здравствуйте!
    Очень хорошая статья и сам php-класс. Всё по уму.
    Подскажите пожалуйста, какой порт указывать в этой строке
    $mailSMTP = new SendMailSmtpClass(‘логин’, ‘пароль’, ‘хост’, ‘порт’, ‘кодировка письма’);
    если у меня сайт на виртуальном хостинге REG.RU (НЕ бесплатном) и я хочу заменить mail() на smtp с авторизацией используя почту домена на том-же сервере? Или — как узнать номер порта?
    ‘хост’ — если я правильно понимаю, должен быть «localhost»?

  19. Хотелось-бы добавить… Маловато у вас заголовков в классе. У меня самописная функция вместо обычной mail() и там я использую побольше заголовков (думаю — это важно для НЕпопадания в СПАМ), если кому-то это необходимо — то наверное и сами смогут добавить нужные заголовки в класс.
    Только в качестве примера:
    function mail_utf8($t_user = », $t_email = », $from_user = », $from_email = », $subject = », $host=», $message=», $headers = »)
    {
    $to=»=?UTF-8?B?».base64_encode($t_user).»?= «;
    $from=»=?UTF-8?B?».base64_encode($from_user).»?= «;//можно так
    $reply=»=?UTF-8?B?».base64_encode($from_user).»?= «;//а можно и по другому
    $subject=»=?UTF-8?B?».base64_encode($subject).»?=»;
    $headers=»MIME-Version: 1.0\r\n».
    «Reply-To: «.$reply.»\r\n».
    «Date: «.date(‘D, d M Y H:i:s’).» +0300\r\n».
    «Message-ID: \r\n».
    «X-Mailer: PHP-UTF8-Sender v3.0 \r\n». //можно, например «Roundcube Webmail/1.3.6» и ещё добавить «User-Agent: Roundcube Webmail/1.3.6»
    «X-Sender: «.$from_email.»\r\n».
    «Importance: Normal \r\n».
    «Priority: Normal \r\n». //кажется уже устарело, видимо нужно цифрами (нашёл где-то в сети, 2014г) «устанавливает приоритет почты по умолчанию: 1 – высоко, 3 – нормально, 5 – низко.»
    «Precedence: bulk \r\n». //означает — «рассылка»
    «List-Unsubscribe: \r\n». //отписаться от рассылки
    «From: «.$from.»\r\n».
    «Content-type: text/html; charset=UTF-8\r\n».
    «Content-Transfer-Encoding: 8bit\r\n»;
    return mail($to, $subject, $message, $headers); }

  20. Спасибо, всё работает. И с яндексом и с мэйлом. Надо бы изменить пример кода в предыдущем посте (так как сначала пробовал его а он не верен).

  21. Здравствуйте. У меня два вопроса. Первый, нет отправки скрытой копии — после строки $headers.= «To: «.$mailTo.»\r\n»; добавил $headers.= «Bcc: «.$bcc.»\r\n»;

    Как добавить в тело при отправке изображение? Вот такая конструкция — , показывает картинку вар дампом. Но когда письмо приходит ее нет в теле письма?

  22. Добрый день. Огромное спасибо за класс.
    При получении письма после отправки To отображается как
    «undisclosed-recipients»: ;
    Хотя передаю в метод send его как строку. В массив он преобразует корректно.
    Что может быть?

  23. Отличный скрипт, служит много лет уже, спасибо за полезный код)
    Нужна помощь специалиста.
    После переезда на scaleway никак не настроить php7-fpm + nginx, чтобы скрипт не вылетал в Error: 110.Connection timed out — уже почти неделю курю и пока ничего. Таймауты никак вообще не повлияли на работу скрипта, это какая-то мелочь, которую упускаю.
    На старом древнем умирающем серве все отлично работает)

    Куда копать? Что делать? Может сокеты? Пока учусь, гуглю сутками)

    1. Запустил)
      Все сокеты, Iptables и прочие соединения работали отлично по причине того, что Scaleway блокировал SMTP в целях предотвращения спама. Для разблокировки надо зайти в панель управления акком и просто «щелкнуть» переключателем..

  24. Здравствуйте, использую ваш класс на PHP 5.6 windows 10 сборка XAMPP, и на Linux хостинга beget.com.
    На windows всё работает, а на хостинге всё проходит успешно, но письмо не приходит. Пользуюсь учётной записью google, авторизация и отправитель — один email.
    Вот код, использующий ваш класс:
    function send($emailFrom, $emailTo, $letterHeader, $letterBody, $serverAccountEmail,
    $serverAccountPassword, $serverAccountHost = ‘ssl://smtp.gmail.com’, $serverAccountPort = 465) {
    $mailSMTP = new SendMailSmtpClass($serverAccountEmail, $serverAccountPassword,
    $serverAccountHost, $serverAccountPort);
    $from = array($emailFrom, $emailFrom);
    $emailToStr = is_array($emailTo) ? $emailToStr = implode(«, «, $emailTo) : $emailTo;
    return $mailSMTP->send($emailToStr, $letterHeader, $letterBody, $from);
    }
    send(‘mymail@gmail.com’, ‘mymail@gmail.com’, ‘my theme’, ‘body str’, ‘mymail@gmail.com’, ‘mypassword’);

    1. Забыл добавить.
      На Linux тоже PHP 5.6
      функция send возвращает true.
      На почте gmail нет открытых сеансов в истории от smtp.

      1. Нашёл проблему. Как оказалось, тоже autorization error. Вылечилось настройкой gmail. Зашёл по ссылке открывающей доступ и отправил одно письмо с хостинга.

  25. Добрый день.
    Проблема следующая: на виртуальном сервере (Denwer) почта уходит без проблем.
    На хостинге (рег.ру) при отправке возникает ошибка «Error: 113.No route to host «.
    настройки скрипта в обоих случаях одинаковые:
    $mailSMTP = new SendMailSmtpClass(‘info@мойсайт.ru’, ‘пароль’, ‘mail.мойсайт.ru’, 25, «utf-8»);
    $from = array(
    «мойсайт», // Имя отправителя
    «info@мойсайт.ru» // почта отправителя
    );
    $to = ‘target@mail.ru’;

    в чем ошибка?

  26. Спасибо автору за труд. Жаль, что он забросил обновление кода. Спасибо комментаторам, которые помогают нормализовать код.
    У меня вопрос: как вместе с ошибками (сообщениями исключений) получать бы и ответ сервера. Прошу не плеваться smtp протокол я узнал только вчера, а ооп для меня тайна священная есть.
    Как прописать в коде чтобы не прописанное сообщение выводилось как ошибка, а еще и часть ответа на запрос сервера?
    Спасибо тем, кто откликнется.
    Для нубов как и я поясню: проблема, что часть сообщений не отправляется на последнем (до выхода) шаге. Т.е. все проходит, а само сообщение не отправляется (проверено). Для разбора с Яндексом (там днс хостится) нужны ответы сервера, а как их технически выковырять — не знаю. Ошибка: E-mail didn’t sent (это для поиска).

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*

code