Отправка почты средствами PHP

Работая над проектом, мне пришлось создать специфичную «анкету соискателя» в котором надо была отправлять всю анкету на указные за ране e-mail адрес, и я сразу же вспомнил про PHP функцию mail().


bool mail ( string to, string subject, string message [, string additional_headers [, string additional_parameters]])

Обязательные параметры:
  • E-mail получателя
  • Заголовок письма
  • Текст письма

Необязательные параметры:
  • Дополнительные заголовки письма
  • Дополнительные параметры командной строки

Возвращаемое значение:
  • true, если письмо было принято к доставке
  • false, в противном случае.


Простейший пример

<?php 
mail("E-mail получателя", "Загаловок", "Текст письма \n 1-ая строчка \n 2-ая строчка \n 3-ая строчка"); 
?>


Перейдем к более сложному примеру


<?php 
$to  = "<mail@example.com>, " ; 
$to .= "mail2@example.com>"; 

$subject = "Заголовок письма"; 

$message = ' <p>Текст письма</p> </br> <b>1-ая строчка </b> </br><i>2-ая строчка </i> </br>';

$headers  = "Content-type: text/html; charset=windows-1251 \r\n"; 
$headers .= "From: От кого письмо <from@example.com>\r\n"; 
$headers .= "Reply-To: reply-to@example.com\r\n"; 

mail($to, $subject, $message, $headers); 
?>


В начале мы определяем кому адресовано письмо, за это отвечает переменная &to, если же получателей несколько человек, то записываем через запятую адреса эл. почты.

Переменные $subject и $message, не буду описывать, это и так понятно.

В нашем примере переменная $headers состоит из 3-строк:
  • В первой строчке ми определяем ты отправляемого письма-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 .= "From: $user_email <$user_email>\r\n"; 
$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);
}
// удаление файла

Поделиться публикацией

Похожие публикации

Комментарии 19

    +3
    Серьезно? 2019 год на дворе. Скрывайте в черновик.
    Это же в документации все есть.

    UPD:
    С телефона не заметил. Все вопросы к RigelGL
    Приглашён
    21 марта 2019 в 20:01 по приглашению пользователя RigelGL
      +1

      Плюс еще cp1251...

      +5
      Отправлять письмо в Windows-1251 закодированным в Base64? Оставлять заголовки (Subject) в raw utf-8? Не создавать text/plain часть при наличии text/html? Отправлять письма напрямую, а не через свой SMTP-сервер?
      В общем, все способы отправить письмо в спам.
      Спрячьте и не никому этот код не показывайте.
        0
        Наоборот оставьте, с пометкой НЛО «вот, как НЕ НАДО писать статьи».
        0
        Хоть через PHP, хоть напрямую цепляться telnet'ом — не будет никакой разницы в ценности(отсутствии) статьи, и так уже все расписано по этой теме вдоль и поперек, только обычно вредных советов подкидывают.
          +3
          Добавлю к приведущим коментариям что в наши дни нужно использовать библиотеки типа SwiftMailer и подобные, потому что email штука довольно сложная и есть очень много нюансов.
            +4

            Вы бы ещё показали, как echo() пользоваться… И ладно, если бы синтаксических ошибок в тексте и в самом коде не было.

              0

              [сарказм]
              Отличная и полезная статья, а главное — актуальная для 2019го.
              Реквестую статью про strtr и str_replace.
              [/ссрказм]

                0
                «Неправильно ты, дядя Федор, бутерброд ешь»

                Функция mail дергает локальный, для сервера на котором работает PHP-скрипт, MTA — а это потенциальный источник проблем:

                • локальный MTA может отсутствовать
                • локальный MTA может давно и прочно прописаться во всех blacklist-ах какие только бывают и администратор сервера может не торопиться его оттуда вытаскивать
                • локальный MTA может упасть и администратор может забить на это на денек другой
                • локальный MTA может вызывать у получателей серьезные сомнения относительно того, не СПАМ ли это
                • mail, как написано в документации, норовит открывать и закрывать соединение с MTA при каждом вызове, что негативно сказывается на производительности


                Мораль — используйте полноценный почтовый сервер и обращайтесь к нему через SMTP (для удобства есть соответствующие библиотеки, например PHPMailer)
                  0

                  Локальный MTA вполне можно настроить, чтобы он пересылал письма через другой сторонний сервер. Если отправка писем идёт прямо во время генерации страницы на севере, то локальный MTA правильнее. Меньше шансов получить тормоза из-за сетевых проблем на удаленном почтовом сервере.

                    0
                    Можно, если сервер (физический или виртуальный) ваш собственный и вы обладаете навыками администрирования.
                  0

                  Машина времени, однако (без обид). Но вы (автор) как то запоздали на пару лет.

                    +8
                    Тут не на пару, а на добрый десяток лет.
                    0
                    Каждый раз удивляюсь таким статьям. Что побуждает авторов такое писать… Уже сколько их заминусили, а они все появляются и появляются.
                      +1
                      Даже не знаю где могу это использовать. Большинство писем отправленных таким способом будут улетать в спам.
                        0
                        Попробую сделать эту статью полезной для Хабросообщества, вот вам Code Review данного куска кода:

                        1. Двойные кавычки и лишние переменные
                        $subject = "тема письма"; 
                        Все строки, которые не содержат управляющие символы \n\r или подстановки переменных, рекомендуется использовать одинарные кавычки. И лучше вынести в константы то, что не меняется в процессе выполнения кода.

                        2. Расположение и название файла
                        $filename = "file.doc";
                        // название файла
                        
                        $filepath = "files/file.doc";
                        // месторасположение файла
                        Тут есть ряд комментариев:
                        • Путь до файла лучше указывать с использованием магической переменной __DIR__
                        • Также лучше работать с абсолютным путем, использую функцию realpath()
                        • Переменную $filename не нужно задавать, можно получить ее из сформированного пути функцией basename($filepath)


                        3. Комментарии снизу
                        Комментарии в коде обычно оставляют либо на той же строке, если это //, либо над строкой, которую планируете прокомментировать.

                        4. Формирование многострочной переменной
                        Для улучшения читаемости кода, лучше не конкатинировать много строк, а использовать HEREDOC или NOWDOC:
                        $mailheaders=<<<HEADERS
                        MIME-Version: 1.0;
                        Content-Type: multipart/mixed; boundary="$boundary"
                        From: $user_email <$user_email>
                        Reply-To: $user_email
                        HEADERS;


                        5. Нет корректной обработки ошибок
                        $multipart .= chunk_split(base64_encode(iconv("utf8", "windows-1251", $message)));
                        Если хоть одна функция поведет себя не так, как ожидается, то весь кусок кода непредсказуемо отработает.
                        if (!$fp) 
                        { 
                            print "Не удается открыть файл22"; 
                            exit(); 
                        }
                        Не информативная ошибка, тем более с какими-то непонятными цифрами 22. Рекомендуется выводить более доступный текст ошибки. Например «При чтении файла {$filepath} возникла ошибка.»

                        6. Чтение файлаЕсли понадобилось читать файл, но не обязательно использовать потоки, можно вытащить контент тем же самым file_get_contents.

                        7. Нет кавычек
                        $message_part .= \r\n;
                        Не уверен, что этот код вообще отработает.

                        8. Удаление файла
                        //удаляем файлы через 60 сек.
                        if (time_nanosleep(5, 0)) {
                            unlink($filepath);
                        }
                        Если это файл, который будет запускаться из cli, то еще может быть ок, но тоже не ясно зачем. А если этот скрипт будет запускаться через вебсервер, то скорее всего он отвалится по timeout.

                        9. Код оформлен не по PSR

                        P.S. Если что-то пропустил, то дополняйте, коллеги!
                          0

                          Это очень забавный комментарий. В стиле, я не знаю, "Вы тут представили телегу без лошади как средство передвижения. Чтобы сделать её более полезной для общества, вот мои замечания: колеса лучше перекрасить в чуть более розовый цвет, борта лучше сделать не из дерева, а из картона потому что красивше и вот еще на узорчиках лучше листики заменить на цветочки."


                          Все эти замечания не делают код полезнее. Чтобы сделать его полезнее, его надо переписать, целиком. С использованием современных инструментов. О чем и говорили все предыдущие комментаторы.


                          Все что написано вверху — это мелкие придирки, половина из которых — это вкусовщина про цветочки. Какие кавычки использовать и применять ли хередок — это исключительно на вкус автора.


                          При этом построчная конкатенация является стандартом при составлении заголовков, поскольку упрощает отладку, позволяя произвольно комментировать отдельные заголовки. Плюс такой формат гарантирует использование строго определенных символов перевода строки, а не тех, что настроены в редакторе по умолчанию.


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


                          Без обид, но чтобы сделать нормальный code review, надо сначала научиться кодить самому. Пока у вас получилось не code review, а cosmetic review. Ваш обзор не делает код лучше, он делает его чуть красивше и более подходящим под ваши субъективные вкусы.

                            0
                            Это очень забавный комментарий. В стиле, я не знаю, «Вы тут представили комментарии по телеге без лошади, которую представили как средство передвижения. И ваши комментарии по цвету колес и бортам из картона не делают из этой телеги средство передвижения. Да и узорчики из цветочков не всем подходят и это вкусовщина. Вместо добавления своих замечаний, я представлюсь Д'Артаньяном на белом коне и налью желчи. „

                            Все эти замечания не делают код полезнее.
                            Никто и не говорил, что код от моих замечаний станет полезнее. Это замечания, которые нужны для того, чтобы прочитавший в своих проектах так не писал.

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

                            Без обид, но чтобы сделать нормальный code review, надо сначала научиться кодить самому. Пока у вас получилось не code review, а cosmetic review. Ваш обзор не делает код лучше, он делает его чуть красивее и более подходящим под ваши субъективные вкусы.
                            Какие обиды? Судя по вашим унылымбесполезным статьям в профиле, мой “cosmetic review» даже ничего для этой статьи. Без обид.
                          0
                          (удален, не в ту ветку написал)

                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                          Самое читаемое