Как грамотно отправлять почту из скриптов (в частности — на PHP) / Habr
Первая часть текста взята из инструкции хостинг-провайдера Netangels. Вторая — авторская.Отправка почты из скриптов на PHP — вещь, которая очень часто встречается в веб-приложениях. К сожалению, как показывает практика, большинство разработчиков используют эту функцию неправильно, допуская в своих скриптах одни и те же ошибки. В результате оказывается, что письмо получателю пришло в неверной кодировке, просто не дошло, или дошло, но отображается совсем не так, как этого хотел автор.
Для того, чтобы быть уверенным, что ваше сообщение отправляется действительно верно, необходимо иметь по меньшей мере базовые представления о формате почтового сообщения. Формат почтового сообщения описан в нескольких стандартизирующих документах, основными из которых являются RFC 822 (описывает формат передачи простого текста на английском языке) и RFC 2045 и далее (описывает расширения этого формата для передачи произвольных данных).
Формат почтового сообщения
Ниже приведен самый простой пример текстового сообщения, составленного в соответствии с приведенными выше стандартами и готового к отправке.
From: =?windows-1251?b?0J7RgtC/0YDQsNCy0LjRgtC10LvRjD89?= <[email protected]>Именно в таком формате клиент для отправки почты (MS Outlook или Mozilla Thunderbird) подготавливает сообщение, а затем отправляет его получателю (кстати, большинство почтовых клиентов позволяют просмотреть исходный код сообщения, в Mozilla Thunderbird, например, для этого служит комбинация клавиш Ctrl+U). Задача нашего скрипта языке PHP — добиться точно такого же формата письма.
To: =?windows-1251?b?0J/QvtC70YPRh9Cw0YLQtdC70Yw/PQ==?= <[email protected]>
Subject: =?windows-1251?b?0Y3RgtC+INGC0LXQvNCwINGB0L7QvtCx0YnQtdC90LjRjz89?=
Content-Type: text/plain; charset=«windows-1251»
Content-Transfer-Encoding: 8bitЭто почтовое сообщение на русском языке
Содержит несколько строк
Грамотное использование русских символов в заголовках почтового сообщения
Итак, в явном виде русский текст в заголовке присутствовать не должен, поэтому для того, чтобы включить его туда, этот текст предварительно нужно закодировать. Стандарты описывают способ кодирования «запрещенных» символов. Общий формат выглядит так:
=? кодировка? способ кодирования? закодированный текст?=Кодировка может быть любой из списка «windows-1251», «koi8-r», «utf-8» и т.д. Во всех случаях, как правило, кодировка сообщения будет совпадать с кодировкой в которой работает сайт. То есть в большинстве случаев это будет «windows-1251», реже — «utf-8».
Способ кодирования указывает на то, каким именно образом русские символы будут преобразованы в безопасный набор. Способа определяется два: так называемый «Q-encoding» (обозначается одной буквой «Q») и «Base64» (обозначается одной буквой «B»).
К сожалению, штатной функции, которая бы могла бы обычную строку преобразовать в Q-encoded текст, в PHP нет, зато есть функция, которая умеет выполнять аналогичное преобразование в Base64. Итак, PHP код правильного создания заголовка темы почтового сообщения может выглядеть следующим образом:
$subject = «=?windows-1251?b?». base64_encode($_POST[«subject»]). «?=»;Здесь предполагается, что в переменной $_POST[«subject»] у вас содержится тема почтового сообщения, записанная по-русски в кодировке windows-1251.
Адрес отправителя или получателя может быть записан в виде «[email protected]» или в виде «Имя пользователя <[email protected]>». Во втором случае имя пользователя необходимо преобразовать так же, как в предыдущем примере. Ниже приведен пример, в котором предполагается, что в переменной $_POST[«username»] содержится имя пользователя, а в переменной $_POST[«email»] его электронный адрес:
$sender = «=?windows-1251?B?». base64_encode($_POST[«username»]). «?= <«. $_POST[«email»]. «>»;
Content-type: multipart/???
С этим заголовком знаком любой разработчик, которому доводилось решать проблемы отправки писем с вложениями или HTML письмами. И зачастую письма, сформированные без использования библиотек вроде PEAR::Mail_mime отображаются не очень корректно. Практика показывает, что если при формировании письма жестко придерживаться стандарта, которы задается в RFC (в частности — RFC 2046) — подавляющее большинство клиентских программ (включая таких любителей придерживаться стандартов, как Mozilla Thunderbird) отображает письмо корректно. Далее мы будем исходить из того, что читатель этого документа представляет себе основной синтаксис команд и понимает, что таке boundary и почему необходимо указывать Content-type для каждой из частей письма. Постараемся отметить основные ошибки.
Ошибка первая — неверный subtype
- mixed — используется, когда в рамках одного почтового сообщения имеется несколько независимых друг от друга, и равнозначных частей. Самый простой пример такого письма — сообщение с вложением.
related — используется, когда в одном почтовом сообщении содержится несколько частей, формирующих один итоговый документ. Яркий пример — HTML письмо с картинками. Запомните, по стандарту только в этом случае должны работать ссылки на Contend-id элементов (вида <img src=«cid:image»>).
Помните и применяйте по назначению.Ошибка вторая — неверный порядок частей
Порядок частей, в котором они указаны в письме, зачастую имеет ключевое значения для того, как будет отображаться сообщение у клиента.- mixed — порядок частей для наших задач не имеет значения.
alternative — части должны быть расставлены по порядку, от более простых к более сложным. RFC регламентирует процесс выбора одной из версий письма клиентом пользователя примерно так: «В общем случае, почтовый клиент должен отображать последнюю доступную ему версию документа». Т.е. при формировании текстовой и HTML-версий письма необходимо вперед поставить текстовую.
related — первой в очереди должна идти основная часть (HTML документ, например). Следом — все остальные. По большому счету, стандартом регламентирован специальный параметр «start», который указывает на основную часть документа, но этим лучше не злоупотреблять.Ошибка третья — выбор только одного субтипа
Зачастую разработчик, формирующий из программы письмо забывает, что любая из частей письма может так же иметь Content-type: multipart, а значит можно выстроить некоторое подобие древовидной структуры, гарантирующей, что каждая из частей письма займет правильное место. Вот как примерно может выглядеть структура письма, имеющего текстовую и HTML версию (HTML с картинками), а так же приложенный документ MS Word:- Content-type: multipart/mixed
- Content-type: multipart/alternative
- Content-type: text/plain
Content-type: multipart/related- Content-type: text/html
Content-type: image/jpeg
Content-type: image/jpeg
Content-type: application/msword - Content-type: text/html
И напоследок — еще пара рекомендаций
- Всегда делайте text/plain вариант письма — никто не может предсказать, как именно будут читать Ваше письмо.
Не ленитесь и придерживайтесь стандартов.
Если интересно — http://people.dsv.su.se/~jpalme/ietf/mhtml-test/mhtml.html тут есть несколько примеров.
- Content-type: text/plain
- Content-type: multipart/alternative
- Content-type: multipart/mixed
- mixed — порядок частей для наших задач не имеет значения.
habr.com
PHP mail под Windows / Habr
В этой статье я хочу рассказать об отправке почты из php скриптов под Windows.
Америку я, конечно, не открою, но надеюсь, что кому-то эта статья будет полезна или просто сэкономит время.
С точки зрения php программиста отправка почты выполняется с помощью стандартной функции mail()
. И вот тут у многих начинающих разработчиков возникает проблема. Скрипт, прекрасно работающий на сервере хостера, выдает ошибки на локальном компьютере.
Обычно эти ошибки имеют примерно такое описание:Warning: mail() [function.mail]: Failed to connect to mailserver at "localhost" port 25, verify your "SMTP" and "smtp_port" setting in php.ini or use ini_set() in E:\www\simplemail\mailer.php on line ......
Дело в том, что функция mail сама по себе почту не отправляет, она просто вызывает программу sendmail, которая в дистрибутив web сервера и php интерпретатора не входит (и не должна).
Sendmail, в свою очередь, для отправки почты использует SMTP сервер.
Таким образом, чтобы php скрипт мог отправлять почту нужно установить и настроить sendmail и SMTP сервер.
Версию sendmail для Windows можно скачать здесь.
Установка и настройка выполняется в три этапа.
1) Распаковываем архив
2) Вносим изменения в файл php.ini:
[mail function]
SMTP =
sendmail_from =
sendmail_path = "C:\wamp\sendmail\sendmail.exe -t"
Как видите, нужно только указать путь к sendmail чтобы php мог ее найти.
3) Настраиваем sendmail. Все настройки находятся в файле sendmail.ini (расположен в папке с sendmail).
Но перед тем как приступать к настройке пару слов об SMTP сервере. Вам совсем не обязательно устанавливать сервер на вашем компьютере. Многие почтовые сервисы предоставляют бесплатный доступ к своим серверам.
Ниже я покажу пример настройки sendmail для работы с SMTP сервером mail.ru, но, естественно, вы выбрать любой другой.
Итак, открываем sendmail.ini и устанавливаем следующие параметры:
smtp_server=smtp.mail.ru
; адрес SMTP сервераsmtp_port=25
; порт SMTP сервера
default_domain=mail.ru
; домен по-умолчанию
error_logfile=error.log
; файл в который будет записываться лог ошибок
debug_logfile=debug.log
; очень полезная на этапе отладки опция. Протоколируются все операции, которые выполняет sendmail
[email protected]
; имя вашего аккаунтаauth_password=account_password
; ваш пароль
; следующие три опции используются если перед авторизацией на SMTP сервере требуется авторизация на POP3 сервереpop3_server=pop.mail.ru
[email protected]
pop3_password=account_password
; параметр для команды MAIL FROM[email protected]
hostname=mail.ru
Теперь не забудьте перезапустить web сервер, чтобы изменения вступили в силу.
Чтобы протестировать работу почты напишем простенький скрипт:
01 <html xmlns="http://www.w3.org/1999/xhtml"> 02 <head> 03 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 04 <title>Simple Mail</title> 05 </head> 06 <body> 07 <?php 08 $addr = $_POST['addr']; 09 $theme = $_POST['theme']; 10 $text = $_POST['text']; 11 if (isset($addr) && isset($theme) && isset($text) 12 && $addr != "" && $theme != "" && $text != "") { 13 if (mail($addr, $theme, $text, "From: [email protected]")) { 14 echo "<h4>Сообщение отправлено</h4>"; 15 } 16 else { 17 echo "<h4>При отправке сообщения возникла ошибка</h4>"; 18 } 19 } 20 ?> 21 <form action="mailer.php" method="post"> 22 <p> 23 <label for="addr">eMail:</label> 24 <input type="text" name="addr" size="30" /> 25 </p> 26 <p> 27 <label for="theme">Тема письма:</label> 28 <input type="text" name="theme" size="30" /> 29 </p> 30 <p> 31 <label for="text">Текст письма:</label> 32 <textarea rows="10" cols="20" name="text"></textarea> 33 </p> 34 <p> 35 <input type="submit" value="Отправить" /> 36 </p> 37 </form> 38 </body> 39 </html>
Он создает форму с тремя полями для ввода адреса, темы и содержания письма. Нажатие на кнопку «Отправить» отправит запрос этому же скрипту (строка 21).
Если данные введены, то будет вызвана функция mail (строка 13), которая и отправит письмо. В случае успешной отправки функция возвращает true, в противном случае — false.
Как видите, ничего сложного в настойке почты нет.
Удачи!
Источник: кросспостинг из моего блога – www.simplecoding.org.
habr.com
Отправка писем через SMTP на PHP
<?php
$config[‘smtp_username’] = ‘[email protected]’; //Смените на адрес своего почтового ящика.
$config[‘smtp_port’] = ‘465’; // Порт работы.
$config[‘smtp_host’] = ‘ssl://smtp.yandex.ru’; //сервер для отправки почты
$config[‘smtp_password’] = ‘пароль’; //Измените пароль
$config[‘smtp_debug’] = true; //Если Вы хотите видеть сообщения ошибок, укажите true вместо false
$config[‘smtp_charset’] = ‘utf-8’; //кодировка сообщений. (windows-1251 или utf-8, итд)
$config[‘smtp_from’] = ‘МегаСервис’; //Ваше имя — или имя Вашего сайта. Будет показывать при прочтении в поле «От кого»
function smtpmail($to=», $mail_to, $subject, $message, $headers=») {
global $config;
$SEND = «Date: «.date(«D, d M Y H:i:s») . » UT\r\n»;
$SEND .= ‘Subject: =?’.$config[‘smtp_charset’].’?B?’.base64_encode($subject).»=?=\r\n»;
if ($headers) $SEND .= $headers.»\r\n\r\n»;
else
{
$SEND .= «Reply-To: «.$config[‘smtp_username’].»\r\n»;
$SEND .= «To: \»=?».$config[‘smtp_charset’].»?B?».base64_encode($to).»=?=\» <$mail_to>\r\n»;
$SEND .= «MIME-Version: 1.0\r\n»;
$SEND .= «Content-Type: text/html; charset=\»».$config[‘smtp_charset’].»\»\r\n»;
$SEND .= «Content-Transfer-Encoding: 8bit\r\n»;
$SEND .= «From: \»=?».$config[‘smtp_charset’].»?B?».base64_encode($config[‘smtp_from’]).»=?=\» <«.$config[‘smtp_username’].»>\r\n»;
$SEND .= «X-Priority: 3\r\n\r\n»;
}
$SEND .= $message.»\r\n»;
if( !$socket = fsockopen($config[‘smtp_host’], $config[‘smtp_port’], $errno, $errstr, 30) ) {
if ($config[‘smtp_debug’]) echo $errno.»<br>».$errstr;
return false;
}
if (!server_parse($socket, «220», __LINE__)) return false;
fputs($socket, «HELO » . $config[‘smtp_host’] . «\r\n»);
if (!server_parse($socket, «250», __LINE__)) {
if ($config[‘smtp_debug’]) echo ‘<p>Не могу отправить HELO!</p>’;
fclose($socket);
return false;
}
fputs($socket, «AUTH LOGIN\r\n»);
if (!server_parse($socket, «334», __LINE__)) {
if ($config[‘smtp_debug’]) echo ‘<p>Не могу найти ответ на запрос авторизаци.</p>’;
fclose($socket);
return false;
}
fputs($socket, base64_encode($config[‘smtp_username’]) . «\r\n»);
if (!server_parse($socket, «334», __LINE__)) {
if ($config[‘smtp_debug’]) echo ‘<p>Логин авторизации не был принят сервером!</p>’;
fclose($socket);
return false;
}
fputs($socket, base64_encode($config[‘smtp_password’]) . «\r\n»);
if (!server_parse($socket, «235», __LINE__)) {
if ($config[‘smtp_debug’]) echo ‘<p>Пароль не был принят сервером как верный! Ошибка авторизации!</p>’;
fclose($socket);
return false;
}
fputs($socket, «MAIL FROM: <«.$config[‘smtp_username’].»>\r\n»);
if (!server_parse($socket, «250», __LINE__)) {
if ($config[‘smtp_debug’]) echo ‘<p>Не могу отправить комманду MAIL FROM: </p>’;
fclose($socket);
return false;
}
fputs($socket, «RCPT TO: <» . $mail_to . «>\r\n»);
if (!server_parse($socket, «250», __LINE__)) {
if ($config[‘smtp_debug’]) echo ‘<p>Не могу отправить комманду RCPT TO: </p>’;
fclose($socket);
return false;
}
fputs($socket, «DATA\r\n»);
if (!server_parse($socket, «354», __LINE__)) {
if ($config[‘smtp_debug’]) echo ‘<p>Не могу отправить комманду DATA</p>’;
fclose($socket);
return false;
}
fputs($socket, $SEND.»\r\n.\r\n»);
if (!server_parse($socket, «250», __LINE__)) {
if ($config[‘smtp_debug’]) echo ‘<p>Не смог отправить тело письма. Письмо не было отправленно!</p>’;
fclose($socket);
return false;
}
fputs($socket, «QUIT\r\n»);
fclose($socket);
return TRUE;
}
function server_parse($socket, $response, $line = __LINE__) {
global $config;
while (@substr($server_response, 3, 1) != ‘ ‘) {
if (!($server_response = fgets($socket, 256))) {
if ($config[‘smtp_debug’]) echo «<p>Проблемы с отправкой почты!</p>$response<br>$line<br>»;
return false;
}
}
if (!(substr($server_response, 0, 3) == $response)) {
if ($config[‘smtp_debug’]) echo «<p>Проблемы с отправкой почты!</p>$response<br>$line<br>»;
return false;
}
return true;
}
?>
i-leon.ru