Отправка почты из PHP: как написать правильно

» Главная  » Поддержка » Статьи » Отправка почты из PHP: как написать правильно

Отправка почты из скриптов на PHP -- функция, которая очень часто встречается в веб-приложениях. К сожалению, как показывает практика, большинство разработчиков используют ее неправильно, допуская в своих скриптах одни и те же ошибки. В результате оказывается, что письмо получателю пришло в неверной кодировке, просто не дошло или вообще неумело написанная форма отправки сообщения была использована для рассылки спама.

Формат почтового сообщения

Для того чтобы быть уверенным, что ваше сообщение отправляется действительно верно, необходимо иметь по меньшей мере базовые представления о формате почтового сообщения. Формат почтового сообщения описан в нескольких стандартизирующих документах, основными из которых являются RFC 822 (описывает формат передачи простого текста на английском языке) и RFC 2045 (описывает расширения этого формата для передачи произвольных данных).

Ниже приведен самый простой пример текстового сообщения, составленного в соответствии с приведенными выше стандартами и готового к отправке:

From: =?windows-1251?b?0J7RgtC/0YDQsNCy0LjRgtC10LvRjD89?= <putin@kremlin.ru>
To: =?windows-1251?b?0J/QvtC70YPRh9Cw0YLQtdC70Yw/PQ==?= <nospam@flexihost.com.ua>
Subject: =?windows-1251?b?0Y3RgtC+INGC0LXQvNCwINGB0L7QvtCx0YnQtdC90LjRjz89?=
Content-Type: text/plain; charset="windows-1251"
Content-Transfer-Encoding: 8bit

Это почтовое сообщение на русском языке.
Содержит несколько строк.

Именно в таком формате клиент для отправки почты (MS Outlook, TheBat! или Mozilla Thunderbird) подготавливает сообщение, а затем отправляет его получателю (кстати, большинство почтовых клиентов позволяют просмотреть исходный код сообщения, в Mozilla Thunderbird, например, для этого служит комбинация клавиш Ctrl+U). Задача нашего скрипта на языке 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@example.com" или в виде "Имя пользователя user@example.com". Во втором случае имя пользователя необходимо преобразовать так же, как в предыдущем примере. Ниже приведен пример, в котором предполагается, что в переменной $_POST["username"] содержится имя пользователя, а в переменной $_POST["email"] - его электронный адрес:

$sender = "=?windows-1251?B?" . base64_encode($_POST["username"]) . "?= <" . $_POST["email"] . ">";

Функция mail()

Отправка почтовых сообщений в большинстве скриптов выполняется системной функцией mail(). Описание синтаксиса функции mail всегда можно найти в оригинальном руководстве. Эта функция принимает всего 5 параметров, из которых три являются обязательными, а остальные два - опциональными:

  • to - Электронный адрес получателя сообщения
  • subject - Тема сообщения
  • message - Тело сообщения
  • additional_headers - дополнительные заголовки
  • additional_parameters - дополнительные параметры

На самом деле функция mail() просто формирует строку следующего вида:

$additional_headers
To: $to
Subject: $subject

$message

а затем передает ее на обработку стандартной UNIX'овой команде отправки почты, которая носит имя sendmail. Сравнивая то, что выдает mail(), с тем, что должно получиться (см. пример выше), можно составить точный план подготовки переменных для передачи в функцию:

  1. Закодировать поле Subject с использованием base64, как в примере выше.
  2. Закодировать поле To.
  3. В случае необходимости создать $additional_headers, самостоятельно сформировав все необходимые заголовки (например, добавив поле "From:") и разделив эти заголовки парой символов "rn".

После этого сформированный набор параметров можно передавать на вход функции mail().

Работа над ошибками с помощью additional_parameters

Как уже упоминалось выше, функция mail() для отправки почты просто вызывает стандартную команду sendmail, при необходимости передавая ей дополнительные параметры. В каком случае может возникнуть необходимость их использования? Самый часто встречающийся случай - проблема с адресом отправителя. Этот адрес нередко изменяется функцией sendmail на адрес вида "имяпользователянасерверехостинга@адрессерверахостинга.ru". Чтобы избежать такого поведения, необходимо передать команде параметр "-femail@отправителя.ru" (обратите внимание на формат строки: "минус-эф", а затем без пробелов электронный адрес).

Защита от спама

Спамеры очень часто для рассылки используют плохо написанные формы отправки почты на PHP. Дело в том, что стандарт допускает использование нескольких получателей, которые могут быть перечислены через запятую в заголовке "To", а также использование произвольного количества специальных заголовков с именем "Сс" (копия) и "Bcc" (скрытая копия). Предположим, что в Вашей форме есть поле темы, которое без изменений транслируется в заголовок "Subject". Для того чтобы отправить произвольное сообщение на тысячу адресов, спамеру достаточно в поле Subject вписать примерно такой текст:

Hello
Cc: a@yahoo.com
Cc: b@yahoo.com
...
Cc: zzzz@google.com

Таким образом отправляемое письмо будет дополнено заголовками "Cc" и почтовая программа, обнаружив все эти заголовки в тексте письма, примется рассылать его всем получателям из списка. Аналогичная ситуация и с переменными $additional_headers и $to - любое из них при удачном стечении обстоятельств может быть использовано злоумышленниками в своих интересах.

Борьба с этим явлением может вестись двумя способами:

  1. Проверка всего пользовательского ввода и фильтрация опасных символов (т.е символов "r" и "n"). Эти символы нужно либо заменять на пробелы, либо отказываться обрабатывать некорректно введенные параметры. Например, замену можно выполнить так:

    $from = preg_replace("/[\r\n]/", " ", $_POST["sender"]);
  2. Выполнение кодирования Base64, помимо прочего, защищает и от спамеров, т.к. "вытягивает" закодированный текст в одну строку.

Как все это сделать проще

Существует по меньшей мере три варианта упрощения жизни при работе с формой отправки почты.

Способ первый

Использование готовых решений для отправки почты. В качестве примера можно привести класс PHPMailer, который легко позволяет реализовать все возможности, описанные выше, и еще целый ряд того, о чем не было упомянуто.

Способ второй

Использование конструктора сайтов. Более подробную информацию о конструкторе можно найти по ссылке. Если говорить коротко, то конструктор позволяет без особого труда создать простой сайт, в который, в числе прочего, будет включена грамотная реализация формы отправки сообщений.

Способ третий

Установка приложений для всех клиентов хостинга. Все клиенты нашего хостинга имеют возможность бесплатной установки ряда приложений на свои сайты. Установка приложений выполняется буквально в два клика, после чего вы получаете в свое распоряжение уже настроенный и полностью готовый к работе модуль. Точно также, в два клика, можно установить и написанную нами форму отправки сообщений.

Способы оплаты
Банковский перевод WebMoney Безналичный платеж Картой Visa Картой Mastercard Privat24 Оплата в терминалах Liqpay
Яндекс.Метрика