пʼятниця, 21 грудня 2007 р.

Надсилання пошти з PHP: mail(), SMTP та помилки історичних прикладів

З надсиланням електронної пошти рано чи пізно стикається кожен PHP-програміст, і проста на вигляд задача швидко обростає нюансами. У 2007 році я знайшов корисний FAQ Trustmaster й зберіг його, щоб і самому пригадувати роботу з mail(), сокетами та класом Mail.

Автор FAQ — Trustmaster. Обговорення: http://forum.sources.ru/index.php?showtopic=68017. У цитованому матеріалі також було доповнення користувача «Рысь» від 16 серпня 2007 року про завершення рядків.

Функція mail(): параметри та результат

У FAQ 2007 року сигнатура функції виглядала так:

bool mail(string to, string subject, string message
[, string additional_headers [, string additional_parameters]]);

to задає адресата, subject — тему, message — тіло листа. Через additional_headers додають поштові заголовки, зокрема From, Cc чи Bcc. Це заголовки електронного листа, а не HTTP. additional_parameters передає додаткові параметри налаштованій програмі надсилання, якщо використовується відповідний транспорт.

Робота mail() залежить від конфігурації PHP та поштового середовища. Тут треба розрізняти формування повідомлення і спосіб його передавання серверу.

Приклад із первинної публікації, збережений без виправлення:

mail("john@doe.com", "PHP mail() Test", "Это письмо отправлено функцией mail() из PHP скрипта",
"From: admin@microsoft.comrnX-Mailer: E-mail Terminator v.1000") or die("Ошибка: не получилось отправить письмо!");

Фрагмент rnX-Mailer не є правильним записом роздільника рядків. У рядкових заголовках потрібне належне завершення рядка; зовнішні дані не повинні давати змогу підставити сторонні заголовки. Наведена адреса admin@microsoft.com — частина старого прикладу, а не адреса, від імені якої слід надсилати власну пошту.

За документацією PHP, true від mail() означає прийняття листа до доставки, а не гарантоване надходження адресату. MIME-вкладення потребують правильного формування повідомлення; відсутність окремого аргументу «файл» не робить їх принципово неможливими.

Історичний SMTP-код на сокетах

Цей код показує задум діалогу з сервером, але в наведеному вигляді не є готовим SMTP-клієнтом:

function sock_mail($host, $to, $from, $subj, $message, $type)
{
if($type=="") $type="text/plain"; // Определям тип по умолчанию
// Соединение
$fp = fsockopen($host, 25); // Подключаемся на 25 порт сервера $host
// Приветствие
$log .= fgets($fp); // Читаем приветствие сервера
fputs($fp, "HELO: $host"); // Привет, сервер smile.gif
$log .= fgets($fp); // Читаем ответ
fputs($fp, "MAIL FROM:<$from>"); // Определяем пользователя
$log .= fgets($fp); // Читаем ответ
fputs($fp,"RCPT TO:<$to>"); // Определяем получателя
$log .= fgets($fp); // Читаем ответ
fputs($fp, "DATA"); // Приветствие окончено, теперь приступим к делу
$log .= fgets($fp); // Читаем ответ
// Заголовки
fputs($fp, "X-Mailer: Sock_Mail v.1.0"); // Название клиента (необязательно)
fputs($fp, "Reply-To: $from"); // Адрес, на который идут ответы (необязательно)
fputs($fp, "From: $from"); // Отправитель
fputs($fp, "Subject: $subj"); // Тема
fputs($fp, "MIME-Version: 1.0"); // Версия MIME (необязательно)
fputs($fp, "Content-Type: $type"); // Тип содержимого
fputs($fp,""); // Пустая строка
// Содержимое
fputs($fp, $message);
// Конец диалога
fputs($fp, ".");
$log .= fgets($fp); // Читаем ответ
fputs($fp, "QUIT"); // Сообщаем о выходе
$log .= fgets($fp); // Читаем ответ
// Завершение соединения
fclose($fp); // Закрываем сокет
return $log; // Возвращаем ответы сервера.
}

У ньому немає правильних завершень рядків у записаних командах; HELO: має хибну форму, не перевіряється успіх з’єднання й очікувані коди відповідей, не реалізовано SMTP-авторизацію та захищений транспорт. Читання одного рядка не охоплює всі багаторядкові відповіді. Завершення DATA та рядки з початковою крапкою також потрібно обробляти за протоколом.

Отже, висновок первинного FAQ про роботу «з будь-яким сервером» був надмірним. Правила SMTP описано у RFC 5321; це пізніша за допис 2007 року редакція протоколу.

Бібліотеки та клас Mail із FAQ

Автор FAQ протиставляв обгортки над mail() власному модифікованому класу. Стверджувати, що більшість сучасних бібліотек мають ті самі обмеження, за цим історичним порівнянням не можна.

Створення та налаштування об’єкта Mail у прикладі Trustmaster:

$m = new Mail(); // Теперь $m - объект класса Mail
$m->Host("mail.myhost.com"); // Будем отправлять писмо с mail.myhost.com
$m->Username("admin"); // Используем пользователя admin
$m->Password("sWordFiSH"); // Пароль - sWordFiSH
$m->Content_type("text/html"); // Письмо в виде HTML
$m->autoCheck(true); // Будем проверять адреса
$m->Subject("How to make million dollars per day."); // Без комментариев
$m->From("user@host.com"); // Отправляем с адреса user@host.com

Це демонстраційні дані з давнього FAQ. Далі в ньому описано такі методи:

  • Host() — вибір сервера, у прикладі localhost або mail.myhost.com.
  • Username(), Password() — облікові дані SMTP-авторизації.
  • Content_type() — тип вмісту, зокрема text/html.
  • autoCheck() — перевірка адрес, за описом вимкнена за замовчуванням.
  • Subject() — тема.
  • From() — адреса відправника, за описом nobody@localhost за замовчуванням.
  • ReplyTo() — адреса для відповідей.
  • To(), Cc(), Bcc() — основні та додаткові адресати, включно з прихованою копією.
  • Body() — текст і необов’язкове кодування.
  • Organization() — назва організації.
  • Priority() — значення від 1 (найвищий) до 5 (найнижчий), 3 — звичайний.
  • Attach() — файл, необов’язковий MIME-тип і disposition; за старим описом типовим був inline.
  • Send() — надсилання.
  • Get() — перегляд сформованого листа.

У копії FAQ для частини методів замість викликів повторювався приклад mail() з маркерами 000–777. Такий фрагмент не показує, як викликати ReplyTo(), Body() чи Attach(); самі призначення методів наведено в переліку вище.

FAQ посилався на вкладення sock_mail.php і mail.php, але самих файлів у цьому дописі немає. Без реалізації класу неможливо перевірити його сумісність, перевірку адрес, формування MIME чи обіцянку відсутності недоліків.

Для робочого застосунку потрібна підтримувана реалізація з параметрами вашого поштового постачальника, коректним формуванням повідомлень і перевіркою помилок. Чинна документація mail().

Немає коментарів:

Навантажувальне тестування K2 ERP: що перевірити до пікової зміни

Демонстраційна база швидко відкривається, презентація переконлива, а справжня перевірка починається перед відправленням машин: склад проводи...