Оглавление:
Введение. Значение почтовых писем
Без почты никуда. Именно по почте мы получаем «волшебные» письма подтверждения на сервисах различных родов и мастей. Именно на почту приходят письма «обратной связи». Практически ни одно веб-приложение или веб-сайт ни обходятся без отправки почты. Поэтому, можно сказать, что отправка почты на php является актуальной проблемой среди программистов и разработчиков. PHP отправка почты не случайна, ведь практически все динамические сайты используют этот язык программирования. В этой статье я постараюсь объяснить, как написать правильный скрипт отправки почты на php, минуя частые ошибки программирования в этой стезе.
Формат сообщения
Как и везде сейчас, в почтовых письмах тоже есть свои стандарты (форматы). Перед конструированием формы отправки необходимо ознакомиться с документами, освещающими стандарты отправки почты:
Приведу пример готового к отправке сообщения, написанного в соответствии с обговоренными стандартами:
From: =?windows-1251?b?0J7RgtC/0YDQsNCy0LjRgtC10LvRjD89?= <men7or@gmail.com> To: =?windows-1251?b?0J/QvtC70YPRh9Cw0YLQtdC70Yw/PQ==?= <admin@php.net> Subject: =?windows-1251?b?0Y3RgtC+INGC0LXQvNCwINGB0L7QvtCx0YnQtdC90LjRjz89?= Content-Type: text/plain; charset="windows-1251" Content-Transfer-Encoding: 8bit Это сообщение содержит одну строку и написано на русском языке.
Популярные и всем известные почтовые клиенты (MS Outlook, например) используют именно такой формат для отправления сообщений. К слову, многие из клиентов предоставляют исходный код формата сообщений. Именно такого формата нам необходимо добиться для отправки почты на php.
Электронное письмо содержит две части: в верхней части размещаются заголовки, а в нижней — текст письма. Пустая строка разделяет эти части. Заголовки состоят из строк, в которых содержится тема письма (Subject), имя и адрес отправителя (From), получателя (To) и другая информация. В самом простом случае каждая строка содержит пару «ИмяЗаголовка: ЗначениеЗаголовка». Особенно необходимо подчеркнуть, что, согласно стандартам, в заголовках ни при каких обстоятельствах не должны содержаться русские символы.
Использование русских символов в заголовках
Так как русские символы недопустимы в заголовках, их необходимо закодировать. Стандарты, о которых мы уже упоминали, описывают способ кодирования «запрещенных» символов. Общий формат выглядит так:
=?кодировка?способ кодирования?закодированный текст?=
Кодировка может быть любой из списка «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.
Адрес отправителя или получателя может быть записан в виде «user@php.net» или в виде «Имя пользователя user@php.net». Во втором случае имя пользователя необходимо преобразовать, как в предыдущем примере. Ниже приведен пример, где в переменной $_POST[«username»] содержится имя пользователя, а в переменной $_POST[«email»] — его электронный адрес:
$sender = "=?windows-1251?B?" . base64_encode($_POST["username"]) . "?= <" . $_POST["email"] . ">";
Функция mail()
Отправка почтовых сообщений в большинстве скриптов выполняется системной функцией mail(). Описание синтаксиса функции mail всегда можно найти в оригинальном руководстве php. Эта функция принимает всего 5 параметров, из которых первые три являются обязательными, а последние два — опциональными:
- to — Электронный адрес получателя сообщения
- subject — Тема сообщения
- message — Тело сообщения
- additional_headers — дополнительные заголовки
- additional_parameters — дополнительные параметры
На самом деле функция mail() просто формирует строку следующего вида:
$additional_headers To: $to Subject: $subject $message
Затем передает ее на обработку стандартной UNIX-команде отправки почты, которая носит имя /usr/sbin/sendmail. Сравнивая то, что выдает mail(), с тем, что должно получиться (см. пример выше), можно составить точный план подготовки переменных для передачи в функцию:
- Закодировать поле Subject с использованием base64, как в примере выше.
- Закодировать поле To.
- В случае необходимости создать $additional_headers, самостоятельно сформировав все необходимые заголовки (например, добавив поле «From:») и разделив эти заголовки парой символов «\r\n».
После этого сформированный набор параметров можно передавать на вход функции mail().
Работа над ошибками с помощью additional_parameters
Как уже упоминалось выше, функция mail() для отправки почты просто вызывает стандартную команду sendmail, при необходимости передавая ей дополнительные параметры. В каком случае может возникнуть необходимость их использования? Самый часто встречающийся случай — проблема с адресом отправителя. Этот адрес нередко изменяется функцией sendmail на адрес вида «имя_пользователя_на_сервере_хостинга@адрес_сервера_хостинга.ru». Чтобы избежать такого поведения, необходимо передать команде параметр «-femail@отправителя.ru» (обратите внимание на формат строки: «минус-эф», а затем без пробелов электронный адрес).
Защита от спама
Спамеры очень часто для рассылки используют плохо написанные формы отправки почты на PHP. Дело в том, что стандарт допускает использование нескольких получателей, которые могут быть перечислены через запятую в заголовке «To», а также использование произвольного количества специальных заголовков с именем «Сс» (копия) и «Bcc» (скрытая копия). Предположим, что в Вашей форме есть поле темы, которое без изменений транслируется в заголовок «Subject». Для того чтобы отправить произвольное сообщение на тысячу адресов, спамеру достаточно в поле Subject вписать примерно такой текст:
Hello Cc: a@gmail.com Cc: b@gmail.com ... Cc: zzzz@gmail.com
Таким образом отправляемое письмо будет дополнено заголовками «Cc» и почтовая программа, обнаружив все эти заголовки в тексте письма, примется рассылать его всем получателям из списка. Аналогичная ситуация и с переменными $additional_headers и $to — любое из них при удачном стечении обстоятельств может быть использовано злоумышленниками в своих интересах.
Борьба с этим явлением может вестись двумя способами:
- Проверка всего пользовательского ввода и фильтрация опасных символов (т.е символов «\r» и «\n»). Эти символы нужно либо заменять на пробелы, либо отказываться обрабатывать некорректно введенные параметры. Например, замену можно выполнить так:
$from = preg_replace("/[\r\n]/", " ", $_POST["sender"]);
- Выполнение кодирования Base64, помимо прочего, защищает и от спамеров, т.к. «вытягивает» закодированный текст в одну строку.
Отправка почты PHP просто
Существует два варианта упрощения жизни при работе с формой отправки почты.
- Использование готовых решений для отправки почты. В качестве примера можно привести класс PHPMailer, который легко позволяет реализовать все возможности, описанные выше, и еще целый ряд того, о чем не было упомянуто.
- Использование конструктора сайтов. Более подробную информацию о конструкторе можно найти по ссылке. Если говорить коротко, то конструктор позволяет без особого труда создать простой сайт, в который, в числе прочего, будет включена грамотная реализация формы отправки сообщений.