Отправка почты средствами PHP
Работая над проектом, мне пришлось создать специфичную «анкету соискателя» в котором надо была отправлять всю анкету на указные за ране e-mail адрес, и я сразу же вспомнил про PHP функцию mail().
bool mail ( string to, string subject, string message [, string additional_headers [, string additional_parameters]])
- E-mail получателя
- Заголовок письма
- Текст письма
- Дополнительные заголовки письма
- Дополнительные параметры командной строки
- true, если письмо было принято к доставке
- false, в противном случае.
Простейший пример
Перейдем к более сложному примеру
Текст письма 1-ая строчка 2-ая строчка '; $headers = "Content-type: text/html; charset=windows-1251 \r\n"; $headers . ; $headers .= "Reply-To: reply-to@example.com\r\n"; mail($to, $subject, $message, $headers); ?>
В начале мы определяем кому адресовано письмо, за это отвечает переменная &to, если же получателей несколько человек, то записываем через запятую адреса эл. почты.
Переменные $subject и $message, не буду описывать, это и так понятно.
- В первой строчке ми определяем ты отправляемого письма-HTML и кодировку windows-1251.
- В 2-ом мы указываем от кого пришло письмо.
- В 3-ем указываем e-mail адрес, для ответа на письмо.
А теперь самое интересное отправка письма c вложением (attachment)
$subject = "тема письма"; $message ="Текст сообщения"; // текст сообщения, здесь вы можете вставлять таблицы, рисунки, заголовки, оформление цветом и т.п. $filename = "file.doc"; // название файла $filepath = "files/file.doc"; // месторасположение файла //исьмо с вложением состоит из нескольких частей, которые разделяются разделителем $boundary = "--".md5(uniqid(time())); // генерируем разделитель $mailheaders = "MIME-Version: 1.0;\r\n"; $mailheaders .="Content-Type: multipart/mixed; boundary=\"$boundary\"\r\n"; // разделитель указывается в заголовке в параметре boundary $mailheaders . ; $mailheaders .= "Reply-To: $user_email\r\n"; $multipart = "--$boundary\r\n"; $multipart .= "Content-Type: text/html; charset=windows-1251\r\n"; $multipart .= "Content-Transfer-Encoding: base64\r\n"; $multipart .= \r\n; $multipart .= chunk_split(base64_encode(iconv("utf8", "windows-1251", $message))); // первая часть само сообщение // Закачиваем файл $fp = fopen($filepath,"r"); if (!$fp) < print "Не удается открыть файл22"; exit(); >$file = fread($fp, filesize($filepath)); fclose($fp); // чтение файла $message_part = "\r\n--$boundary\r\n"; $message_part .= "Content-Type: application/octet-stream; name=\"$filename\"\r\n"; $message_part .= "Content-Transfer-Encoding: base64\r\n"; $message_part .= "Content-Disposition: attachment; filename=\"$filename\"\r\n"; $message_part .= \r\n; $message_part .= chunk_split(base64_encode($file)); $message_part .= "\r\n--$boundary--\r\n"; // второй частью прикрепляем файл, можно прикрепить два и более файла $multipart .= $message_part; mail($to,$subject,$multipart,$mailheaders); // отправляем письмо //удаляем файлы через 60 сек. if (time_nanosleep(5, 0)) < unlink($filepath); >// удаление файла
Отправка почты через mail() в PHP
Чтобы отправить почту любому адресату через PHP, нужно использовать встроенную функцию mail(). Как бы ни казалось простой эта функция. Она всегда может вызывать загвоздки даже у опытных программистов.
Разберем простой пример php формы, где мы будем отправлять письмо с html содержимым на произвольный email.
В форме два поля name и msg , которые будет передавать пользователь нам на ящик, нажав кнопку Отправить ( otprav ). Передачу данных обычно делают через метод post. Также стоит обратить внимание на action=»» . Внутри кавычек ставится путь к php файлу обработчику, который запустится после отправки форму (нажатия на кнопку otprav). Если action пуст, как в примере, то значит php обработчик должен быть в файле с формой.
Теперь после формы создадим php обработчик для отправки письма.
$to = «12test16@mail.ru»;
$subject = «Письмо с сайта»;
$charset = «utf-8»;
$headerss =»Content-type: text/html; charset=$charset\r\n»;
$headerss.=»MIME-Version: 1.0\r\n»;
$headerss.=»Date: «.date(‘D, d M Y h:i:s O’).»\r\n»;
$msg = «Имя: «.$_POST[«name»].»\n»;$msg .= «Сообщение: «.$_POST[«msg»].»\n»;
mail($to, $subject, $msg, $headerss);
print ««;
>
Разберем код подробнее.
$to — куда отправить письмо;
$subject — тема письма
$charset — кодировка вашего сайта/страницы
$headerss — технический заголовок письма, в котором есть запись text/html, которая означает, что в письмо пользователь может добавлять html теги. Чтобы отключить эту возможность замените на text/plain.
$msg — формируем текст сообщения для отправки
mail. — собирает все введенные данные и отправляет их адресату
print. — после отправки страницы обновляет ее и выдает сообщение, что отправка завершена.
Из этого примера, думаю вам станет понятнее, как создавать простые формы на отправку писем. Кстати, здесь не используются параметры from (от кого письмо). Так как многие хостинги отключают эту возможность намеренно.
Каждая строка должна быть отделена символом CRLF (\r\n). Строки не должны быть длиннее 70 символов.
Предостережение
(Только для Windows) Если PHP передаёт данные напрямую SMTP-серверу и в начале строки стоит точка, то она будет удалена. Чтобы избежать этого замените все такие точки на две.
$text = str_replace ( «\n.» , «\n..» , $text );
?>?php
additional_headers (необязательный)
Строка или массив, которые будут вставлены в конец отправляемых заголовков письма.
Обычно используется для добавления дополнительных заголовков (From, Cc, and Bcc). Несколько дополнительных заголовков должны быть разделены CRLF (\r\n). Если для составления этого заголовка используются внешние данные, то они должны быть проверены для избежания инъекций нежелательных заголовков.
Если передан массив, то его ключи будут именами заголовка, а значения значениями.
Замечание:
До PHP 5.4.42 и 5.5.27, параметр additional_headers не имел защиты от инъекции. Так что пользователи должны удостовериться, что передаваемые заголовки безопасны и содержат только заголовки. т.е. не содержат несколько переводов строк подряд, что стартует тело сообщения.
Замечание:
При отправке письмо должно содержать заголовок From . Он может быть установлен с помощью параметра additional_headers , или значение по умолчанию может быть установлено в php.ini .
Если заголовок отсутствует, будет сгенерировано сообщение об ошибке вида Warning: mail(): «sendmail_from» not set in php.ini or custom «From:» header missing . Заголовок From также определяет заголовок Return-Path при отправке напрямую через SMTP (только Windows).
Замечание:
Если сообщения не отправляются, попробуйте использовать только LF (\n). Некоторые агенты пересылки сообщений Unix (особенно » qmail) автоматически заменяют LF на CRLF (что приводит к двойному CR, если использовалось CRLF). Используйте эту меру в крайнем случае, так как это нарушает » RFC 2822.
additional_params (необязательный)
Параметр additional_params может быть использован для передачи дополнительных флагов в виде аргументов командной строки для программы сконфигурированной для отправки писем, указанной директивой sendmail_path . Например, можно установить отправителя письма при использовании sendmail с помощью опции -f .
Параметр автоматически экранируется функцией escapeshellcmd() , чтобы не допустить выполнение команд. Но escapeshellcmd() позволяет добавлять дополнительные параметры. В целях безопасности рекомендуется проверять и очищать этот параметр.
Так как escapeshellcmd() применяется автоматически, то нельзя использовать некоторые символы, допустимые к использованию в email-адресах некоторыми RFC. mail() не допускает такие символы, поэтому в программах, в которых они требуются, рекомендуется использовать альтернативы для их отправки (например фреймворки или библиотеки).
Пользователь, под которым работает веб-сервер должен быть добавлен в список доверенных в конфигурации sendmail для того чтобы избежать добавления заголовка ‘X-Warning’ при указании отправителя с помощью опции (-f). Для пользователей sendmail — это файл /etc/mail/trusted-users .
Возвращаемые значения
Возвращает true , если письмо было принято для передачи, иначе false .
Важно заметить, что то что письмо было принято для передачи вовсе НЕ означает что оно достигло получателя.
Список изменений
| Версия | Описание |
|---|---|
| 7.2.0 | Параметр additional_headers может принимать значения типа массив. |
Примеры
Пример #1 Отправка письма.
Использование функции mail() для отправки простого письма:
// Сообщение
$message = «Line 1\r\nLine 2\r\nLine 3» ;
?php
// На случай если какая-то строка письма длиннее 70 символов мы используем wordwrap()
$message = wordwrap ( $message , 70 , «\r\n» );
// Отправляем
mail ( ‘caffeinated@example.com’ , ‘My Subject’ , $message );
?>
Пример #2 Отправка письма с дополнительными заголовками.
Добавление простых заголовков, сообщающих почтовому агенту адреса From и Reply-To:
$to = ‘nobody@example.com’ ;
$subject = ‘the subject’ ;
$message = ‘hello’ ;
$headers = ‘From: webmaster@example.com’ . «\r\n» .
‘Reply-To: webmaster@example.com’ . «\r\n» .
‘X-Mailer: PHP/’ . phpversion ();
?php
mail ( $to , $subject , $message , $headers );
?>
Пример #3 Отправка письма с дополнительными заголовками, переданными массивом
В этом примере посылается то же письмо, что и в примере выше, но дополнительные заголовки задаются массивом (доступно с PHP 7.2.0).
$to = ‘nobody@example.com’ ;
$subject = ‘the subject’ ;
$message = ‘hello’ ;
$headers = array(
‘From’ => ‘webmaster@example.com’ ,
‘Reply-To’ => ‘webmaster@example.com’ ,
‘X-Mailer’ => ‘PHP/’ . phpversion ()
);
?php
mail ( $to , $subject , $message , $headers );
?>
Пример #4 Отправка письма с дополнительными аргументами командной строки.
Параметр additional_params может быть использован для передачи дополнительных параметров программе, используемой для отправки писем с помощью директивы sendmail_path .
mail ( ‘nobody@example.com’ , ‘the subject’ , ‘the message’ , null ,
‘-fwebmaster@example.com’ );
?>?php
Пример #5 Отправка HTML-сообщения
С помощью функции mail() также можно отправить и HTML-письмо.
// несколько получателей
$to = ‘johny@example.com, sally@example.com’ ; // обратите внимание на запятую
?php
// тема письма
$subject = ‘Birthday Reminders for August’ ;
// текст письма
$message = ‘
Here are the birthdays upcoming in August!
| Person | Day | Month | Year |
|---|---|---|---|
| Johny | 10th | August | 1970 |
| Sally | 17th | August | 1973 |
‘ ;
// Для отправки HTML-письма должен быть установлен заголовок Content-type
$headers [] = ‘MIME-Version: 1.0’ ;
$headers [] = ‘Content-type: text/html; charset=iso-8859-1’ ;
// Дополнительные заголовки
$headers [] = ‘To: Mary , Kelly ‘ ;
$headers [] = ‘From: Birthday Reminder ‘ ;
$headers [] = ‘Cc: birthdayarchive@example.com’ ;
$headers [] = ‘Bcc: birthdaycheck@example.com’ ;
// Отправляем
mail ( $to , $subject , $message , implode ( «\r\n» , $headers ));
?>
Замечание:
Для отправки HTML или других комплексных сообщений рекомендуется использовать PEAR-пакет » PEAR::Mail_Mime.
Примечания
Замечание:
Реализация SMTP (только Windows) функции mail() в Windows во многом отличается от реализации в sendmail. Во-первых, она не использует локальную программу для составления писем, а работает непосредственно с сокетами, что означает что необходим почтовый агент ( MTA ), ожидающий соединений на сокете (может быть как на локальном так и на удалённом сервере).
Во-вторых, дополнительные заголовки вроде: From: , Cc: , Bcc: и Date: интерпретируются в первую очередь не, MTA , а PHP.
Поэтому параметр to не должен быть адресом вида «Something «. Команда mail может неправильно интерпретировать этот адрес во время передачи данных MTA.
Замечание:
Не следует использовать функцию mail() для отправки большого количества писем в цикле. Функция открывает и закрывает соединение с SMTP-сервером для каждого письма, что не очень эффективно.
Для отправки большого количества сообщений обратите внимание на пакеты » PEAR::Mail и » PEAR::Mail_Queue.
Смотрите также
- mb_send_mail() — Отправка закодированного сообщения
- imap_mail() — Отправить email
- » PEAR::Mail
- » PEAR::Mail_Mime
Отправка почты из PHP: как написать правильно
В данной статье рассмотрена отправка почты из PHP с детальным описанием функции mail(), использования русских символов и защиты от спама.
Отправка почты из скриптов на PHP – функция, которая очень часто встречается в веб-приложениях. К сожалению, как показывает практика, большинство разработчиков используют ее неправильно, допуская в своих скриптах одни и те же ошибки. В результате оказывается, что письмо получателю пришло в неверной кодировке, просто не дошло или вообще неумело написанная форма отправки сообщения была использована для рассылки спама.
Формат почтового сообщения
Для того чтобы быть уверенным, что ваше сообщение отправляется действительно верно, необходимо иметь по меньшей мере базовые представления о формате почтового сообщения. Формат почтового сообщения описан в нескольких стандартизирующих документах, основными из которых являются RFC 822 (описывает формат передачи простого текста на английском языке) и RFC 2045 (описывает расширения этого формата для передачи произвольных данных).
Ниже приведен самый простой пример текстового сообщения, составленного в соответствии с приведенными выше стандартами и готового к отправке:
From: =?windows-1251?b?0J7RgtC/0YDQsNCy0LjRgtC10LvRjD89?= To: =?windows-1251?b?0J/QvtC70YPRh9Cw0YLQtdC70Yw/PQ==?= 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"]) . "? subject"]у Вас содержится тема почтового сообщения, записанная по-русски в кодировке windows-1251.Адрес отправителя или получателя может быть записан в виде “user@example.com” или в виде “Имя пользователя user@example.com”. Во втором случае имя пользователя необходимо преобразовать так же, как в предыдущем примере. Ниже приведен пример, в котором предполагается, что в переменной
$_POST["username"]содержится имя пользователя, а в переменной$_POST["email"]- его электронный адрес:$sender = "=?windows-1251?B?" . base64_encode($_POST["username"]) . "?= ";Функция mail()
Отправка почтовых сообщений в большинстве скриптов выполняется системной функцией mail() . Описание синтаксиса функции mail всегда можно найти в оригинальном руководстве. Эта функция принимает всего 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@yahoo.com Cc: b@yahoo.com . Cc: zzzz@google.com
Таким образом отправляемое письмо будет дополнено заголовками “Cc” и почтовая программа, обнаружив все эти заголовки в тексте письма, примется рассылать его всем получателям из списка. Аналогичная ситуация и с переменными $additional_headers и $to - любое из них при удачном стечении обстоятельств может быть использовано злоумышленниками в своих интересах.
Борьба с этим явлением может вестись двумя способами:
-
Проверка всего пользовательского ввода и фильтрация опасных символов (т.е символов “\r” и “\n”). Эти символы нужно либо заменять на пробелы, либо отказываться обрабатывать некорректно введенные параметры. Например, замену можно выполнить так:
$from = preg_replace("/[\r\n]/", " ", $_POST["sender"]);
Как все это сделать проще
Использование готовых решений для отправки почты. В качестве примера можно привести класс PHPMailer, который легко позволяет реализовать все возможности, описанные выше, и еще целый ряд того, о чем не было упомянуто.
