Отправка письма средствами PHP
Мы проделали часть работы. Мы можем с помощью сценария получить данные, которые вводит пользователь в форме. Но пока они видны только самому пользователю. Нам нужно дополнить сценарий таким образом, чтобы данные отсылались нам на почту (или сохранялись в базе данных, чтобы их читать на сайте).
Любое письмо состоит из нескольких элементов: адрес электронной почты отправителя, адрес электронной почты получателя, тема письма, само письмо. Посмотрим, что у нас имеется.
Адрес электронной почты получателя — это ваш электронный адрес, уж его вы знаете.
Тема письма — можем придумать сами. Проявите фантазию.
Само письмо — в принципе мы можем использовать тот же текст, который выводился в сценарии report.php. Только его нужно отформатировать немного, чтобы получить нужную строку. Ведь, как вы помните, в сценарии мы выводили текст в отдельных строках при помощи команды echo с использованием тега для красивого вывода на html-странице.
echo 'Спасибо за заполнение формы.
'; echo 'Кота похитили ' . $when . '
'; echo 'Похитители: ' . $description . '
'; echo 'Ваш email: ' . $email;
Создадим новую переменную $msg, которая будет содержать текст письма:
$msg = 'Спасибо за заполнение формы.'. 'Кота похитили ' . $when . 'Похитители: ' . $description . 'Ваш email: ' . $email;
Мы создали достаточно длинную строку, соединив отдельные части с помощью оператора конкатенации (точки). Если вывести текст, содержащий в новой переменной через команду echo $msg; на той странице с сценарием, то получим приблизительно следующее:
Мы получили текст письма, правда выглядит он пока не слишком опрятным. Можно было добавить пробелов между предложениями или разбить на отдельные строчки, но в целом результат нас устраивает.
Так как письмо — это обычный текст, то здесь нельзя использовать HTML-тег . Для перевода текста на новую строку используется символ новой строки в форме Escape-последовательности ‘\n’.
Попробуем переделать пример:
$msg = 'Спасибо за заполнение формы.\n'. 'Кота похитили ' . $when . '\n'. 'Похитители: ' . $description . '\n'. 'Ваш email: ' . $email;
Снова выводим результат с помощью echo $msg; и смотрим:
Вместо переноса строк мы видим \n как обычный текст, который затесался между нашими словами для письма. Фигня какая-то.
Проблема заключается в том, что PHP по разному обрабатывает строки, заключённые в одинарные или двойные кавычки. В нашем случае, что перенос строк заработал, необходимо использовать двойные кавычки. Попробуем:
$msg = "Спасибо за заполнение формы.\n". "Кота похитили $when\n". "Похитители: $description\n". "Ваш email: $email"; echo $msg;
Мы видим, что символы \n исчезли, но текст всё равно выводится в одну строку. Однако, если вы откроете исходный код страницы, то увидите, что на самом деле текст разбит на отдельные строки. Но браузер игнорирует подобные переносы, поэтому мы не замечаем эффекта переноса строк. Если бы мы выводили строку в текстовый документ, то всё бы работало, как мы хотели. В письме переносы также будут работать.
Обратите внимание на следующую особенность. В примере с двойными кавычками мы вставляли имена переменных прямо в текст без обрамляющий кавычек. PHP самостоятельно подставляет значения переменных в текст. Это очень удобно. Здесь важно понимать разницу между одинарными и двойными кавычками в PHP-коде. Данное объяснение выходит за рамки изучаемого урока.
У нас есть все необходимые компоненты для отправки письма. Осталось скомпоновать в одно целое. Создадим отдельные переменные для каждого элемента письма:
$email = $_POST['email']; // от кого $to /cdn-cgi/l/email-protection" data-cfemail="04676c71676f446a6b76766d772a676b69">[email protected]"; // кому $subject = "Вам письмо"; // тема письма $msg = "Спасибо за заполнение формы.\n". "Кота похитили $when\n". "Похитители: $description\n". "Ваш email: $email";
В PHP есть встроенная функция для отправки письма mail(). Простой вариант функции выглядит следующим образом:
mail($to, $subject, $msg);
Как видите, в этом варианте не используется электронный адрес отправителя. Остальные параметры являются обязательными. На практике используют другой вариант функции с четырьмя параметрами, где нужно указать электронную почту отправителя. Причем, у четвёртого параметра следует обязательно добавить слово From: (с пробелом). Полностью, функция выглядит так:
mail($to, $subject, $msg, 'From: ' . $email);
Мы соединили слово From: с адресом почты через точку (оператор конкатенации) и получили четвёртый параметр для функции.
Если вы хотите также отправить копию и скрытую копию, то следует добавить нужные элементы («Cc: » или «Bcc: «) в четвёртом параметре, отделяя элементы комбинацией символов возврата каретки и новой строки, например так:
"From: " . $from . "\r\nCc: " . $cc
При отправке письма вы можете столкнуться с двумя проблемами. Первая — ваш сервер может не поддерживать функцию mail(). Вам следует обратиться к своему хостеру с этим вопросом или сменить хостера и выбрать хостинг с поддержкой отправки писем.
Вторая проблема связана с русским языком. Исторически сложилось, что некоторые служебные заголовки при отправке писем используют устаревшие кодировки. И если вы будете проверять поступившую почту у себя на компьютере, то можете увидеть кракозябры в теме письма, в сообщении, в обратном адресе. Некоторые почтовые сервера умеют частично определять и конвертировать на лету неправильную кодировку. А если вы привыкли читать почту через почтовые клиенты, то эта проблема может проявиться особенно отчётливо.
Вот рабочий пример, который обычно я использую в своих проектах. Для начала формирую кодировку для темы письма следующим образом:
$subject = "=?utf-8?B?" . base64_encode("здесь тема вашего письма") . "? From: $email\r\nReply-To: $email\r\nReturn-Path: $email\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Transfer-Encoding: 8bit");
Теперь мы умеем создавать форму, получать данные от пользователя и отправлять полученную информацию себе на почту.
PHP отправка письма
С появлением форм обратной связи, гостевых книг, отзывов, форумов и т.д. Появилась потребность отслеживать, когда пользователь ввел, что-то в форму и оставил Вам сообщении. Согласитесь, что не удобно проверять вручную сообщения не зная заранее есть ли оно или нет. Для выхода из этой ситуации нам помогут почтовые сервисы такие как mail.ru, yandex.ru и другие. Возникает вопрос, как связать свой сайт, а точнее форму обратной связи с почтой, чтобы сообщение уходило на почту и Вы могли оперативно реагировать на сообщения с сайта.
Для решения данной задачи нам поможет маленький, но очень шустрый скрипт, который будет отправлять нам сообщения на почту о том, что нам оставили сообщение. В основе скрипта лежит PHP функция
bool mail ( string $to , string $subject , string $message [, string $additional_headers [, string $additional_parameters ]] );
Мы не будем здесь рассматривать отправку письма с вложением, нас интересует только отчет о поступившем сообщении с сайта. Для того чтобы отправить письмо нам нужно три параметра, а именно: отправитель, получатель и сам текст письма. Тело письма мы будем отправлять в HTML разметки. Чтобы почтовый сервер понимал, что мы хотим в теле письма отправить HTML нужно указать Content-type в заголовках почтового сервера.
Пишем скрипт php отправки письма.
'); //Адрес почты от кого отправляем define('KAS_MAIL_AUTOR','Робот доставки '); /**Отпровляем сообщение на почту * @param string $to - Кому * @param string $from - От кого * @param string $title - Заголовок письма * @param string $message - Тело письма */ function sendMail($to, $from, $title, $message) < //Формируем заголовок письма $subject = $title; $subject = '=?utf-8?b?'. base64_encode($subject) .'?='; /*Формируем заголовки для почтового сервера, Говорим серверу что используем HTML*/ $headers = "Content-type: text/html; charset=\"utf-8\"\r\n"; $headers .= "From: ". $from ."\r\n"; $headers .= "MIME-Version: 1.0\r\n"; $headers .= "Date: ". date('D, d M Y h:i:s O') ."\r\n"; //Отправляем данные на ящик if(!mail($to, $subject, $message, $headers)) return 'Ошибка отправки письма!'; else return true; >//Формируем заголовок письма $title = 'Ура нам письмо пришло!'; //Формируем HTML верстку письма для отправки $msg = 'Ура нам письмо пришло!
Это письмо создано автоматически, отвечать на него не нужно!
'; //Вызываем функцию отправки письма if(sendMail(KAS_MAIL_TO, KAS_MAIL_AUTOR, $title, $msg)) echo 'Письмо отправленно. ' ?>
Вот такой простой скрипт php отправки письма. Вам нужно вызывать данную функцию в обработчике вашей формы в случае если форма прошла валидацию.
Функция mail() — самый простой способ отправить письмо с помощью PHP
Для связи с пользователями сайта (и некоем подобии контроля над ними) бывает полезно отправлять им письма с сайта. Например, при регистрации нового пользователя (чтобы они не плодились как кролики в урожайный год для моркови и капусты), можно просить указать их адрес электронной почты, выслать на этот адрес какой-то код и, пока этот код не будет введён на сайте, не считать пользователя зарегистрированным. В PHP есть удобная функция mail() для отправки сообщений на электронную почту. Простейший вариант отправки email с помощью этой функции рассмотрим в этой статье.
Работающий php-скрипт для отправки письма с помощью функции mail()
Как обычно, сперва приведу код программы на php, а потом объясню: как и что работает.
[email protected]' . "\r\n" . 'Reply-To: [email protected]' . "\r\n" . 'X-Mailer: PHP/' . phpversion(); if (isset($_POST['to']) && isset($_POST['subject']) && isset($_POST['message'])) if (mail($_POST['to'], $_POST['subject'], $_POST['message'], $headers)) < echo 'письмо было принято для передачи'; > else < echo 'что-то пошло не так. '; > ?>
Форма для получения данных, которые нужно отправить по электронной почте
Первые 10 строк кода, приведённого выше — это HTML-форма, в которую вводим email, куда будем отправлять письмо, тему письма и собственно сам текст письма. Это поля с именами to , subject и message .
Ниже идёт php-код, обрабатывающий полученные данные из этой формы и, если все поля заполнены, пытается отправить письмо на указанный адрес электронной почты.
PHP функция mail()
Перед тем, как рассматривать код, разберёмся вкратце с php-функций mail() , которая присутствует во всех версиях php и имеет следующий формат:
mail ( string $to , string $subject , string $message [, mixed $additional_headers [, string $additional_parameters ]] ) : bool
- в первой строковой переменной $to должен содержаться получатель или список получателей письма в формате, описанном в RFC 2822, например,
- [email protected]
- [email protected], [email protected]
- User <[email protected]>
- User
, Another User <[email protected]>
Это если вкратце.
Стоит ещё обратить внимание на то, какие значения возвращает функция mail() : возвращает TRUE , если письмо было принято для передачи, иначе FALSE . Так можно отслеживать, что что-то пошло не так при попытке отправить сообщение на электронную почту.
Дополнительные заголовки функции mail() для того, чтобы письмо сразу не попадало в спам
Вернёмся к нашему коду. В строчках 13..14 в переменную $headers мы как раз записываем три заголовка:
- From — адрес отправителя (можно подставить какое угодно мыло, но лучше своё) =)
- Reply-To — адрес, который подставится почтовой программой при попытке получателя ответить на это сообщение.
- X-Mailer — поможет для того, чтобы отследить, кто (какая программа) отправила письмо. Бывает полезно для отлова и отстрела спамеров.
Отправка письма функцией mail() с предварительной проверкой полей перед отправкой
В 16-й строке проверяем, что все поля заполнены. Более полную проверку на соответствие всем требованиям RFM всех заголовков пока писать лень. Кому интересно, могут почитать про валидацию электронной почты (email) из данных формы на стороне сервера с помощью php в → этой статье.
В 17-й строке запускаем функцию mail() и. письмо полетело.
- если полёт нормальный, в 18-й строке выводим зелёное сообщение о том, что всё хорошо;
- если при попытке передать письмо возникли проблемы: функция mail() вернула значение FALSE , сообщаем об этом.
Резюме
Таким образом можно достаточно легко и быстро отправлять сообщения с помощью php-функции mail() , подписываясь Санта Клаусом, Кукусклановцем или Биллом Гейтсом. Но, надеюсь, что прочитав эту статью, никто не решил стать ещё одним рассыльным почтового спама. Для этого нужно знать немного больше. 😉
Но этих сведений будет достаточно, чтобы отправить письмо с сайта пользователю со ссылкой подтверждения регистрации. Что и требовалось. =D
Заберите ссылку на статью к себе, чтобы потом легко её найти!
Раз уж досюда дочитали, то может может есть желание рассказать об этом месте своим друзьям, знакомым и просто мимо проходящим?
Не надо себя сдерживать! 😉Отправка писем на PHP через SMTP
Отправлять письма через PHP намного проще, чем кажется. Всего-то надо сформировать правильный EML, подключиться к SMTP и отправить письмо. Ну ещё может быть, хотя и не факт, надо где-то как-то залогировать отправку, а то потом потеряют письмо, скажут, что и не было никаких писем. И виноватый опять ты, хотя ты бел и пушист. А ещё бы хорошо сделать хоть какую-то обработку ошибок, а то вдруг эксепшин, или серевер устал, или коннект не пошёл, а тут суперважный клиент. И уж совсем замечательно хранить где-то письма на случай «я потеряль», «мне не дошло», «а вышлите мне ещё раз». А ещё мы хотим отправлять письма на сайте, который видел расцвет динозавров. А ещё. мне кажется, что список ещё может расширяться не хуже нашей вселенной.
Для решения всех этих проблем я решил написать небольшой инструмент — ApMailer.
ApMailer
ApMailer — это небольшая библиотека, единственной целью которой является отправка почты. Я постарался сделать её максимально простой и удобной. Вы можете скачать всего один файл и отправлять письма и из консоли, и из web-скриптов!
Подключение ApMailer
Скачайте из репозитория файл mailer.phar или src/lib.php (если не нужна консольная версия). После этого подключите lib.php:
// Если скачали phar include 'phar:///path/to/mailer.phar/lib.php'; // Если скачали исходный код include '/path/to/lib.php';После этого будет доступна функция Mailer() :
Mailer()->init(include 'config.php'); $message = Mailer()->newHtmlMessage(); $message->setSubject($messageSubject); $message->setSenderEmail($messageFrom); $message->addRecipient($messageTo); $message->addContent(file_get_contents('mail-header.html')); $message->addContent($messageText); $message->addContent(file_get_contents('mail-footer.html')); $message->addRelatedFile('signature.png'); if (isset($_FILES['attachment']['size']) && $_FILES['attachment']['size'] > 0) < $message->addAttachmentFile( $_FILES['attachment']['tmp_name'], $_FILES['attachment']['name'], $_FILES['attachment']['type'] ); > Mailer()->sendMessage($message);Инициализация
Перед отправкой писем Mailer надо проинициализировать. Делается это так:
Mailer()->init($config);Конфиг представляет из себя многомерный массив, в котором указываются адрес отправителя по умолчанию, хуки для обработки ошибок и ведения логов и транспортёры:
$config = [ 'defaultFrom' => 'mymail@example.org', 'onError' => function($error, $message, $transport) < echo $error; >, 'afterSend' => function($text, $message, $layer) < echo $text; >, 'transports' => [ // Сохранение всех писем в папке ['file', 'dir' => __DIR__ .'/mails'], // Отправка писем через Yandex, используя SSL и авторизацию ['smtp', 'host' => 'smtp.yandex.ru', 'ssl' => true, 'port' => '465', 'login' => '****@yandex.ru', 'password' => '******'], ], ];В качестве транспортов можно использовать file и smtp . Тип транспорёта всегда должен передаваться первым элементом массива, дальше идут его настройки.
Транспортёр file сохраняет письмо в виде EML в папку. Доступны следующие настройки:
- dir — папка, а которую будут сохраняться письма. Если предполагается много писем, лучше хранить их с разбивкой по дате ‘dir’ => strftime( ‘/path/to/mails/%Y/%m/%d’ )
Транспортёр smtp отправляет письмо через SMTP. Доступны следующие настройки:
- host — адрес SMTP-сервера
- ssl — использовать SSL при подключении (обязательно для google, yandex и других популярных сервисов)
- port — порт подключения (обычно 25 для подключения без SSL и 465 для подклюения с SSL)
- login — логин для авторизации (если логин не указан, то используется подключение без авторизации)
- password — пароль для авторизации (не используется, если логин не указан)
- onError — срабатывает на ошибку транспортёра (удобно делать лог ошибок отправки писем)
- afterSend — срабатывает после отправки письма (удобно делать общий лог отправки писем)
Настройка defaultFrom нужна, чтобы не указывать каждый раз адрес отправителя. Если система не подразумевает работу нескольких человек, которые могут отсылать почту, то этот адрес обычно постоянный.
Рабочий пример
В качестве примера я сделал форму отправки письма:


Отправка почты на старых версиях PHP
Поскольку библиотека умеет работать через консоль, то можно формировать команду, которая сможет отправлять письма. Единственное, что нужно, наличие скомпилированного бинарника PHP 5.6.
function sendMail($message) < $keys = array( 'subject' => '-s', 'from' => '-f', 'text' => '-t', 'reciient' => array('-r'), 'to' => array('-r'), 'related' => array('-i'), 'attachment' => array('-a'), 'config' => array('-c'), ); $args = array(); // Если отправляют HTML if (isset($message['html'])) < $args[] = '--html'; // Подключаем шаблон $textArray = array(); // Header $textArray[] = ''; if (isset($message['html'])) < $textArray[] = join((array) $message['html']); > // Footer $textArray[] = ''; $message['text'] = join($textArray); > foreach ($keys as $key => $argument) < if (!isset($message[$key])) < continue; > if (is_array($argument)) < $argument = array_shift($argument); foreach ((array) $message[$key] as $value) < $args[] = $argument .' '. escapeshellarg($value); > > else < $args[] = $argument .' '. escapeshellarg($message[$key]); > > $command = 'php5.6 /path/to/mailer.phar '. join(' ', $args); exec($command); >;А дальше уже можно отправлять письма:
sendMail(array( 'to' => array('someone@exmaple.org', 'someoneelse@exmaple.org'), 'subject' => 'Привет, мир!', 'html' => 'Hello
', ));
