├── .gitignore ├── example ├── test.jpg ├── test2.jpg ├── test3.txt └── index.php ├── composer.json ├── README.md └── src └── SendMailSmtpClass.php /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | composer.lock 3 | .DS_Store -------------------------------------------------------------------------------- /example/test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ipatov/SendMailSmtpClass/HEAD/example/test.jpg -------------------------------------------------------------------------------- /example/test2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ipatov/SendMailSmtpClass/HEAD/example/test2.jpg -------------------------------------------------------------------------------- /example/test3.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ipatov/SendMailSmtpClass/HEAD/example/test3.txt -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ipatov/smtp-mail", 3 | "type": "library", 4 | "description": "PHP Class to Send Email using Yandex, Gmail, Mail.ru SMTP", 5 | "keywords": ["smtp","mail"], 6 | "homepage": "https://github.com/Ipatov/SendMailSmtpClass", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Ipatov Evgeny", 11 | "email": "admin@vk-book.ru", 12 | "homepage": "https://vk-book.ru", 13 | "role": "Developer" 14 | } 15 | ], 16 | "autoload": { 17 | "psr-4": { 18 | "SmtpMail\\": "src/" 19 | } 20 | }, 21 | "require": {} 22 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Для установки с помощью composer: 2 | composer require ipatov/smtp-mail 3 | 4 | /** 5 | * 13.03.2018 6 | * 7 | * SendMailSmtpClass 8 | * 9 | * Класс для отправки писем через SMTP с авторизацией 10 | * Может работать через SSL протокол 11 | * Тестировалось на почтовых серверах yandex.ru, mail.ru и gmail.com, smtp.beget.com 12 | * 13 | * v 1.1 14 | * Добавлено: 15 | * - Приветствие сервера ehlo в приоритете, если не сервер не ответил, то шлется helo 16 | * - Работа с кодировками utf-8 и windows-1251 17 | * - Возможность отправки нескольким получателям 18 | * - Автоматическое формирование заголовков письма 19 | * - Возможность вложения файлов в письмо 20 | * 21 | * @author Ipatov Evgeniy 22 | * @version 1.1 23 | */ 24 | 25 | UPD 23.12.2019 26 | 1. добавлен метод toCopy для добавления получателя письма в копию 27 | 2. добавлен метод toHideCopy для добавления получателя письма в скрытую копию 28 | 3. комменты к переменным внутри класса дописал 29 | 4. исправлен баг в методе _parseServer 30 | 31 | UPD 21.11.2021 32 | 1. Исправлена отправка через yandex 33 | 2. Добавлена установка через composer: composer require ipatov/smtp-mail 34 | 35 | Подробнее тут: 36 | https://vk-book.ru/novaya-versiya-klassa-sendmailsmtpclass-otpravka-fajlov-cherez-smtp-s-avtorizaciej-po-protokolu-ssl-na-php/ 37 | -------------------------------------------------------------------------------- /example/index.php: -------------------------------------------------------------------------------- 1 | addFile("test.jpg"); 29 | $mailSMTP->addFile("test2.jpg"); 30 | $mailSMTP->addFile("test3.txt"); 31 | 32 | // добавить получателя письма в копию 33 | $mailSMTP->toCopy("test-copy@yandex.ru"); 34 | // $mailSMTP->toCopy("test-copy@vk-book.ru"); 35 | 36 | // добавить получателя письма в скрытую копию 37 | $mailSMTP->toHideCopy("zhenikipatov@yandex.ru"); 38 | 39 | // отправляем письмо 40 | $result = $mailSMTP->send($to, 'Тема письма с копиями ', 'Текст письма', $from); 41 | // $result = $mailSMTP->send('Кому письмо', 'Тема письма', 'Текст письма', 'Отправитель письма'); 42 | 43 | if($result === true){ 44 | echo "Done"; 45 | }else{ 46 | echo "Error: " . $result; 47 | } 48 | -------------------------------------------------------------------------------- /src/SendMailSmtpClass.php: -------------------------------------------------------------------------------- 1 | 21 | * @version 1.2 22 | */ 23 | 24 | namespace SmtpMail; 25 | 26 | class SendMailSmtpClass { 27 | 28 | /** 29 | * 30 | * @var string $smtp_username - логин 31 | * @var string $smtp_password - пароль 32 | * @var string $smtp_host - хост 33 | * @var array $smtp_from - от кого 34 | * @var integer $smtp_port - порт 35 | * @var string $smtp_charset - кодировка 36 | * @var string $boundary - разделитель содержимого письма(для отправки файлов) 37 | * @var bool $addFile - содержит письмо файл или нет 38 | * @var string $multipart - заголовки для письма с файлами 39 | * @var array $arrayCC - массив получателей копии письма 40 | * @var array $arrayBCC - массив получателей скрытой копии письма 41 | * 42 | */ 43 | public $smtp_username; 44 | public $smtp_password; 45 | public $smtp_host; 46 | public $smtp_from; 47 | public $smtp_port; 48 | public $smtp_charset; 49 | public $boundary; 50 | public $addFile = false; 51 | public $multipart; 52 | public $arrayCC; 53 | public $arrayBCC; 54 | 55 | public function __construct($smtp_username, $smtp_password, $smtp_host, $smtp_port = 25, $smtp_charset = "utf-8") { 56 | $this->smtp_username = $smtp_username; 57 | $this->smtp_password = $smtp_password; 58 | $this->smtp_host = $smtp_host; 59 | $this->smtp_port = $smtp_port; 60 | $this->smtp_charset = $smtp_charset; 61 | 62 | // разделитель файлов 63 | $this->boundary = "--".md5(uniqid(time())); 64 | $this->multipart = ""; 65 | } 66 | 67 | /** 68 | * Отправка письма 69 | * 70 | * @param string $mailTo - получатель письма 71 | * @param string $subject - тема письма 72 | * @param string $message - тело письма 73 | * @param array $smtp_from - отправитель. Массив с именем и e-mail 74 | * 75 | * @return bool|string В случаи отправки вернет true, иначе текст ошибки 76 | * 77 | */ 78 | function send($mailTo, $subject, $message, $smtp_from) { 79 | // подготовка содержимого письма к отправке 80 | $contentMail = $this->getContentMail($subject, $message, $smtp_from, $mailTo); 81 | 82 | try { 83 | if(!$socket = @fsockopen($this->smtp_host, $this->smtp_port, $errorNumber, $errorDescription, 30)){ 84 | throw new Exception($errorNumber.".".$errorDescription); 85 | } 86 | if (!$this->_parseServer($socket, "220")){ 87 | throw new Exception('Connection error'); 88 | } 89 | 90 | $server_name = $_SERVER["SERVER_NAME"]; 91 | fputs($socket, "EHLO $server_name\r\n"); 92 | if(!$this->_parseServer($socket, "250")){ 93 | // если сервер не ответил на EHLO, то отправляем HELO 94 | fputs($socket, "HELO $server_name\r\n"); 95 | if (!$this->_parseServer($socket, "250")) { 96 | fclose($socket); 97 | throw new Exception('Error of command sending: HELO'); 98 | } 99 | } 100 | 101 | fputs($socket, "AUTH LOGIN\r\n"); 102 | if (!$this->_parseServer($socket, "334")) { 103 | fclose($socket); 104 | throw new Exception('Autorization error'); 105 | } 106 | 107 | fputs($socket, base64_encode($this->smtp_username) . "\r\n"); 108 | if (!$this->_parseServer($socket, "334")) { 109 | fclose($socket); 110 | throw new Exception('Autorization error'); 111 | } 112 | 113 | fputs($socket, base64_encode($this->smtp_password) . "\r\n"); 114 | if (!$this->_parseServer($socket, "235")) { 115 | fclose($socket); 116 | throw new Exception('Autorization error'); 117 | } 118 | 119 | fputs($socket, "MAIL FROM: <".$smtp_from[1].">\r\n"); 120 | if (!$this->_parseServer($socket, "250")) { 121 | fclose($socket); 122 | throw new Exception('Error of command sending: MAIL FROM'); 123 | } 124 | 125 | $mailTo = str_replace(" ", "", $mailTo); 126 | $emails_to_array = explode(',', $mailTo); 127 | foreach($emails_to_array as $email) { 128 | fputs($socket, "RCPT TO: <{$email}>\r\n"); 129 | if (!$this->_parseServer($socket, "250")) { 130 | fclose($socket); 131 | throw new Exception('Error of command sending: RCPT TO'); 132 | } 133 | } 134 | // если есть кому отправить копию 135 | if(!empty($this->arrayCC)){ 136 | foreach($this->arrayCC as $emailCC) { 137 | fputs($socket, "RCPT TO: <{$emailCC}>\r\n"); 138 | if (!$this->_parseServer($socket, "250")) { 139 | fclose($socket); 140 | throw new Exception('Error of command sending: RCPT TO'); 141 | } 142 | } 143 | } 144 | // если есть кому отправить скрытую копию 145 | if(!empty($this->arrayBCC)){ 146 | foreach($this->arrayBCC as $emailBCC) { 147 | fputs($socket, "RCPT TO: <{$emailBCC}>\r\n"); 148 | if (!$this->_parseServer($socket, "250")) { 149 | fclose($socket); 150 | throw new Exception('Error of command sending: RCPT TO'); 151 | } 152 | } 153 | } 154 | 155 | fputs($socket, "DATA\r\n"); 156 | if (!$this->_parseServer($socket, "354")) { 157 | fclose($socket); 158 | throw new Exception('Error of command sending: DATA'); 159 | } 160 | 161 | fputs($socket, $contentMail."\r\n.\r\n"); 162 | if (!$this->_parseServer($socket, "250")) { 163 | fclose($socket); 164 | throw new Exception("E-mail didn't sent"); 165 | } 166 | 167 | fputs($socket, "QUIT\r\n"); 168 | fclose($socket); 169 | } catch (Exception $e) { 170 | return $e->getMessage(); 171 | } 172 | return true; 173 | } 174 | 175 | 176 | // добавление файла в письмо 177 | public function addFile($path){ 178 | $file = @fopen($path, "rb"); 179 | if(!$file) { 180 | throw new Exception("File `{$path}` didn't open"); 181 | } 182 | $data = fread($file, filesize( $path ) ); 183 | fclose($file); 184 | $filename = basename($path); 185 | $multipart = "\r\n--{$this->boundary}\r\n"; 186 | $multipart .= "Content-Type: application/octet-stream; name=\"$filename\"\r\n"; 187 | $multipart .= "Content-Transfer-Encoding: base64\r\n"; 188 | $multipart .= "Content-Disposition: attachment; filename=\"$filename\"\r\n"; 189 | $multipart .= "\r\n"; 190 | $multipart .= chunk_split(base64_encode($data)); 191 | 192 | $this->multipart .= $multipart; 193 | $this->addFile = true; 194 | } 195 | 196 | // парсинг ответа сервера 197 | private function _parseServer($socket, $response) { 198 | $responseServer = $response; 199 | while (@substr($responseServer, 3, 1) != ' ') { 200 | if (!($responseServer = fgets($socket, 256))) { 201 | return false; 202 | } 203 | } 204 | if (!(substr($responseServer, 0, 3) == $response)) { 205 | return false; 206 | } 207 | return true; 208 | } 209 | 210 | // подготовка содержимого письма 211 | private function getContentMail($subject, $message, $smtp_from, $mailTo){ 212 | // если кодировка windows-1251, то перекодируем тему 213 | if( strtolower($this->smtp_charset) == "windows-1251" ){ 214 | $subject = iconv('utf-8', 'windows-1251', $subject); 215 | } 216 | $contentMail = "Date: " . date("D, d M Y H:i:s") . " UT\r\n"; 217 | $contentMail .= 'Subject: =?' . $this->smtp_charset . '?B?' . base64_encode($subject) . "=?=\r\n"; 218 | 219 | // заголовок письма 220 | $headers = "MIME-Version: 1.0\r\n"; 221 | // кодировка письма 222 | if($this->addFile){ 223 | // если есть файлы 224 | $headers .= "Content-Type: multipart/mixed; boundary=\"{$this->boundary}\"\r\n"; 225 | }else{ 226 | $headers .= "Content-type: text/html; charset={$this->smtp_charset}\r\n"; 227 | } 228 | // $headers .= "From: {$smtp_from[0]} <{$smtp_from[1]}>\r\n"; // от кого письмо 229 | $headers .= 'From: ' . '=?UTF-8?B?' . base64_encode($smtp_from[0]) . '?= ' . '<' . $smtp_from[1] . '>' . "\n"; 230 | $headers .= "To: ".$mailTo."\r\n"; // кому 231 | 232 | // если есть кому отправить копию 233 | if(!empty($this->arrayCC)){ 234 | foreach($this->arrayCC as $emailCC) { 235 | $headers.= "Cc: ".$emailCC."\r\n"; // кому копию 236 | } 237 | } 238 | 239 | // если есть кому отправить копию 240 | if(!empty($this->arrayBCC)){ 241 | foreach($this->arrayBCC as $emailBCC) { 242 | $headers.= "Bcc: ".$emailBCC."\r\n"; // кому копию 243 | } 244 | } 245 | 246 | $contentMail .= $headers . "\r\n"; 247 | 248 | if($this->addFile){ 249 | // если есть файлы 250 | $multipart = "--{$this->boundary}\r\n"; 251 | $multipart .= "Content-Type: text/html; charset=utf-8\r\n"; 252 | $multipart .= "Content-Transfer-Encoding: base64\r\n"; 253 | $multipart .= "\r\n"; 254 | $multipart .= chunk_split(base64_encode($message)); 255 | 256 | // файлы 257 | $multipart .= $this->multipart; 258 | $multipart .= "\r\n--{$this->boundary}--\r\n"; 259 | 260 | $contentMail .= $multipart; 261 | }else{ 262 | $contentMail .= $message . "\r\n"; 263 | } 264 | 265 | // если кодировка windows-1251, то все письмо перекодируем 266 | if( strtolower($this->smtp_charset) == "windows-1251" ){ 267 | $contentMail = iconv('utf-8', 'windows-1251', $contentMail); 268 | } 269 | 270 | return $contentMail; 271 | } 272 | 273 | // добавлении получателя копии 274 | public function toCopy($email){ 275 | $this->arrayCC[] = $email; 276 | } 277 | 278 | // добавлении получателя скрытой копии 279 | public function toHideCopy($email){ 280 | $this->arrayBCC[] = $email; 281 | } 282 | 283 | } --------------------------------------------------------------------------------