Статьи

Расширенный Email в PHP

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

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

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

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

Настройка электронной почты PHP

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

Если вы не используете свой собственный сервер, а вместо этого имеете веб-хостинг с поддержкой PHP, вы можете смело предполагать, что все в этом разделе сделано для вас, и пропустите его.

В разделе, озаглавленном [mail function] в файле php.ini , вы найдете три параметра: SMTP , sendmail_from и sendmail_path . Если ваш сервер работает на компьютере с Windows, вам нужно установить параметр SMTP чтобы он указывал на ваш SMTP-сервер (или SMTP-сервер вашего провайдера, если вы устанавливаете PHP на своем домашнем компьютере). Если вместо этого вы настраиваете PHP на сервере Linux (или другой ОС на основе Unix), вам нужно установить параметр sendmail_path чтобы он указывал на программу sendmail на вашем сервере, передавая ей параметр -t . Вместо этого вы можете использовать опцию SMTP в Linux, если вы не настроили sendmail .

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

Вот как может выглядеть раздел на типичном сервере Windows или на сервере Linux без sendmail:

 [mail function] ; Setup for Windows systems SMTP = smtp.my.isp.net sendmail_from = [email protected] 

А вот как это может выглядеть на сервере Linux с sendmail:

 [mail function] ; Setup for Linux systems sendmail_path = /usr/sbin/sendmail -t sendmail_from = [email protected] 

С этими настройками перезагрузите ваш веб-сервер, и вы готовы к работе!

Отправка простого электронного письма

Это не намного проще, чем процедура отправки простого текстового электронного письма на PHP. Фактически, вы можете сделать это всего одной строкой в ​​PHP-скрипте:

 <?php mail('[email protected]', 'Subject', 'Your message here.'); ?> 

В приведенной выше строке будет отправлено электронное сообщение по [email protected] Subject с темой « Subject » и « Your message here. ‘как тело сообщения. Как вы можете видеть, функция mail PHP делает отправку электронной почты чрезвычайно простой, но есть несколько продвинутых приемов, которые мы можем использовать, чтобы извлечь из этой простой функции больше пользы.

Прежде всего, если почтовая система, настроенная вами в файле php.ini отклоняет сообщение, которое вы пытаетесь отправить (например, если адрес «to» не является действительным адресом электронной почты), эта функция отобразит сообщение об ошибке в браузер пользователя. Однако, как и большинство функций PHP, сообщения об ошибках могут подавляться, если перед именем функции стоит символ @. Объедините это с тем фактом, что функция mail возвращает true или false в зависимости от того, было ли письмо принято системой отправки почты, и у вас есть формула для отправки электронной почты с соответствующей проверкой ошибок:

 <?php if (@mail($to, $subject, $message)) { echo('<p>Mail sent successfully.</p>'); } else { echo('<p>Mail could not be sent.</p>'); } ?> 

Обратите внимание, что только то, что сообщение электронной почты может быть отправлено, не гарантирует его прибытия в пункт назначения. Адрес электронной почты может быть действительным (то есть правильно сформированным), но фактически не существовать. Например, вы можете успешно отправить сообщение по [email protected] то есть функция mail вернет true, но сообщение будет отклонено, поскольку такого пользователя не существует. PHP не предоставляет встроенных средств обнаружения, когда это происходит.

Если вы хотите отправить сообщение нескольким получателям, вы можете просто перечислить их адреса электронной почты один за другим, разделенные запятыми, в первом параметре. Например:

 <?php mail('[email protected], [email protected]', 'An email to two people', 'Message goes here.'); ?> 

Это касается основ работы с mail ; Теперь давайте по-настоящему представимся и рассмотрим заголовки писем и то, что мы можем с ними сделать!

HTML электронная почта и другие заголовки

Так что теперь вы можете отправлять электронную почту из ваших скриптов PHP. Как здорово! Хотя я уверен, что вы уже пьяны от силы, хотели бы вы знать, как отправлять электронную почту в формате HTML? Конечно, вы бы!

Чтобы понять электронную почту в формате HTML, сначала необходимо понять заголовки почты. Любое данное сообщение электронной почты состоит из двух частей: заголовков и тела сообщения. Вот как выглядит простое сообщение, когда ваша почтовая программа получает его от вашего провайдера:

 Return-Path: <[email protected]> Delivered-To: [email protected] Received: ...several lines like this... From: Sender <[email protected]> To: You <[email protected]> Subject: A Simple Message Date: Mon, 11 Feb 2002 16:08:19 -0500 Organization: Sender's Company X-Mailer: Microsoft Outlook, Build 10.0.2616 
 Hi there! <tap> <tap> Is this thing on? 

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

Как видите, каждая строка заголовков начинается с имени заголовка ( From: To: Subject: Date: и т. Д.), За которым следует некоторое значение. Большинство заголовков стандартизированы и имеют конкретное значение, как для вашей почтовой программы, так и для почтовых серверов, которые отвечали за получение сообщения для вас. Также существуют нестандартные заголовки, и все они начинаются с X- (например, X-Mailer: нестандартный заголовок, часто появляется для обозначения программы, которая использовалась для отправки сообщения).

ПРИМЕЧАНИЕ. Если для значения заголовка требуется более одной строки, дополнительные строки должны начинаться с пробела. Мы увидим пример этого в следующем разделе.

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

mail функция PHP позволяет вам указывать свои собственные заголовки, которые он добавляет к тем, которые он генерирует автоматически, чтобы получить ваше сообщение, куда он должен идти. Например, следующий вызов функции mail добавит заголовок X-Mailer: к исходящему сообщению, идентифицируя PHP 4.x как отправляющую программу:

 <?php mail('[email protected]', 'Subject', 'Your message here.', 'X-Mailer: PHP 4.x'); ?> 

Этот необязательный четвертый параметр чаще всего используется для указания адреса «от», отличного от значения по умолчанию, указанного в php.ini . Давайте добавим заголовок From: для этого:

 <?php mail('[email protected]', 'Subject', 'Your message here.', "From: [email protected]: PHP 4.x"); ?> 

Обратите внимание, что поскольку каждый заголовок отображается в одной строке, мы должны разделить два заголовка новым символом строки ( n ), что означает, что мне нужно использовать двойные кавычки вокруг строки заголовка (строки в одинарных кавычках не распознают коды специальных символов, такие как n ).

Дополнительные заголовки также позволяют назначать имена адресам электронной почты, указав их в формате name <email> . Вот снова наш пример, но на этот раз с именами «Отправитель» и «Получатель», прикрепленных к соответствующим адресам:

 <?php mail('[email protected]', 'Subject', 'Your message here.', "To: The Receiver <[email protected]>n" . "From: The Sender <[email protected]>n" . "X-Mailer: PHP 4.x"); ?> 

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

Заголовки cc: и Bcc: предоставляют возможность отправлять копии и скрытые копии сообщения также:

 <?php mail('[email protected], [email protected], [email protected]', 'Subject', 'Your message here.', "To: The Receiver <[email protected]>n" . "From: The Sender <[email protected]>n" . "cc: Interested <[email protected]>n" . "Bcc: Me Too <[email protected]>n" . "X-Mailer: PHP 4.x"); ?> 

Посмотрите, как в первом параметре указаны адреса электронной почты всех получателей, будь то фактические адресаты (Кому), копии (Cc) или скрытые копии (Bcc)? Это нигде не задокументировано, но в ходе моего тестирования я обнаружил, что крайне важно, чтобы вы хотели, чтобы сообщение доходило до всех, кого оно должно, особенно на серверах Windows, где функция mail PHP особенно чувствительна.

Предупреждение об ошибках : Есть две очевидные ошибки в mail функции PHP, о которых я заметил еще в PHP 4.1.0, о которых вы должны знать. Во-первых, заголовок Cc: должен быть напечатан как « cc: » (как указано выше) или « CC: », то есть в прописных или строчных буквах. Версия со смешанным регистром ( Cc: должна работать, но это не так. Во-вторых, на серверах Windows заголовок Bcc: не работает должным образом. Bcc: получатели действительно получают копию сообщения, но заголовки Bcc: не удаляются из сообщения во время отправки, поэтому получатели могут видеть получателей Bcc: просматривая эти строки в заголовках.

Вы спрашиваете, как все это связано с электронной почтой HTML? Ну, несколько специальных заголовков приведут к тому, что тело сообщения будет интерпретироваться как HTML почтовыми клиентами, которые его поддерживают:

<?php mail('[email protected]', 'Subject', '<html><body><p>Your <i>message</i> here.</p></body></html>', "To: The Receiver <[email protected]>n" . "From: The Sender <[email protected]>n" . "MIME-Version: 1.0n" . "Content-type: text/html; charset=iso-8859-1"); ?>

Обратите внимание как на сообщение в формате HTML, так и на два новых заголовка: Mime-Version: и Content-type:

Заголовок MIME-Version: указывает, что будет использоваться стандартный расширенный почтовый формат (MIME обозначает многоцелевые расширения почты Интернета), который позволяет отправлять сообщениям типы содержимого, отличные от простого текста. Затем заголовок Content-type: указывает, что сообщение содержит HTML (и устанавливает для набора символов стандарт для этого формата).

Смешанные сообщения

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

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

Давайте рассмотрим простой пример смешанного сообщения электронной почты, а затем посмотрим на код PHP для его отправки:

 Date: Mon, 11 Feb 2002 16:08:19 -0500 To: The Receiver <[email protected]> From: The Sender <[email protected]> Subject: A simple mixed message MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="==Multipart_Boundary_xc75j85x" 
 This is a multi-part message in MIME format. --==Multipart_Boundary_xc75j85x Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit This is the text portion of the mixed message. --==Multipart_Boundary_xc75j85x Content-Type: text/html; charset="iso-8859-1" Content-Transfer-Encoding: 7bit <html> <body> <p>This is the <b>HTML portion</b> of the mixed message.</p> </body> </html> 

--==Multipart_Boundary_xc75j85x--

После начальных стандартных заголовков в верхней части сообщения у нас есть заголовок MIME-Version: 1.0 который включает расширенные функции электронной почты, которые нам нужны. Заголовок Content-Type: — это то место, где вещи начинают становиться все интереснее:

Content-Type: multipart/alternative; boundary="==Multipart_Boundary_xxc75885"

Мы указываем тип контента multipart/alternative , который является специальным типом, который позволяет нам отправлять сообщение с двумя или более альтернативными версиями сообщения (из которых программа электронной почты получателя выберет наиболее подходящую для отображения). Кроме того, мы используем заголовок Content-Type чтобы установить граничную строку .

Чтобы строки заголовка были короткими, эта часть заголовка появляется во второй строке (как упоминалось в примечании выше, вторая строка должна начинаться с одного или нескольких пробелов, чтобы указать, что это продолжение предыдущей строки).

В этом случае я выбрал « ==Multipart_Boundary_xc75j85x » в качестве строки границы. Эта строка не имеет особого значения, за исключением того, что она вряд ли будет отображаться как часть самого сообщения. Я использовал такие символы, как знаки равенства и подчеркивания, а также полуслучайные строки букв и цифр, чтобы помочь в этом. Затем мы используем эту строку, чтобы разделить наше сообщение на части.

Текст « This is a multi-part message in MIME format. »Для удобства старых почтовых программ, так что у пользователя есть некоторое представление о том, почему электронная почта может выглядеть не совсем так, как ожидалось. С этим отказом от ответственности мы используем нашу границу, чтобы отметить начало первой части нашего сообщения:

 --==Multipart_Boundary_xc75j85x Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit 

Это текстовая часть смешанного сообщения.

Обратите внимание, что мы добавляем две черточки ( -- ) к началу строки границы, когда мы фактически ее используем.

После первой границы начинаем текстовую версию сообщения. Каждая часть сообщения начинается с пары заголовков, чтобы указать тип содержимого и кодировку. В случае текстовой части тип содержимого — text/plain (со стандартным набором символов iso-8859-1 ), а кодировка — 7 7bit (простой текст ASCII). Пустая строка отмечает конец заголовков, за которыми следует тело сообщения.

Затем следует HTML-версия:

 --==Multipart_Boundary_xc75j85x Content-Type: text/html; charset="iso-8859-1" Content-Transfer-Encoding: 7bit 
 <html> <body> <p>This is the <b>HTML portion</b> of the mixed message.</p> </body> </html> 

Заголовки практически идентичны текстовой части, но на этот раз мы указываем text/html в качестве типа содержимого. После тела документа HTML остается только закрывающая граница, к которой мы добавляем две дополнительные черточки в конце, чтобы отметить конец сообщения:

--==Multipart_Boundary_xc75j85x--

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

Вот как мне нравится это делать:

 <?php $semi_rand = md5(time()); $mime_boundary = "==Multipart_Boundary_x{$semi_rand}x"; ?> 

Мы берем текущую временную метку Unix (количество секунд с 1 января 1970 года), заданную функцией time() , и используем алгоритм MD5 для преобразования ее в полуслучайную строку. Эта строка затем используется, чтобы составить часть граничной строки. Не стесняйтесь использовать любой метод для создания ваших граничных строк.

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

Вложения файлов

Вложения файлов работают так же, как смешанная электронная почта, за исключением того, что для сообщения в целом используется другой тип контента ( multipart/mixed вместо multipart/alternative ), и есть новый заголовок Content-Disposition который сообщает почтовому клиенту, как обрабатывать каждый часть сообщения.

Давайте напишем скрипт PHP, который обрабатывает отправку формы, которая содержит отправляемое сообщение электронной почты, возможно, с вложенным файлом, и отправляет его. Я расскажу вам об этом построчно, чтобы к концу у вас был не только полезный фрагмент кода PHP, но и понимание работы файловых вложений. Вы можете скачать скрипт (и форму для него), если вы хотите попробовать его сами.

Сначала мы берем представленные значения и помещаем их в переменные PHP. Большинство людей настроили свои серверы на автоматическое создание глобальных переменных для отправленных значений, но в PHP 4.1 это больше не является значением по умолчанию, поэтому мы делаем это вручную на всякий случай. Поскольку мы хотим принимать файловые вложения, можно с уверенностью предположить, что форма будет отправлена ​​с запросом POST:

 <?php // Read POST request params into global vars $to      = $_POST['to']; $from    = $_POST['from']; $subject = $_POST['subject']; $message = $_POST['message']; 

$_FILES файлы в PHP 4.1 помещаются в специальный массив $_FILES , поэтому мы $_FILES нам значения:

 // Obtain file upload vars $fileatt      = $_FILES['fileatt']['tmp_name']; $fileatt_type = $_FILES['fileatt']['type']; $fileatt_name = $_FILES['fileatt']['name']; 

Для краткости предположим, что необходимые параметры ( $to и $from ) теперь содержат допустимые значения (адреса электронной почты). Обычно мы проверяем их формат с помощью регулярных выражений.

Далее мы используем значение $from для начала создания дополнительных заголовков для электронной почты:

$headers = "From: $from";

Далее мы проверяем переменную $fileatt , которая может содержать или не содержать путь и имя файла к загруженному $fileatt файлу. Мы используем функцию PHP is_uploaded_file чтобы выяснить:

 if (is_uploaded_file($fileatt)) { // Read the file to be attached ('rb' = read binary) $file = fopen($fileatt,'rb'); $data = fread($file,filesize($fileatt)); fclose($file); 

Прочитав данные для вложения файла, нам нужно настроить заголовки сообщений для отправки multipart/mixed сообщения:

  // Generate a boundary string $semi_rand = md5(time()); $mime_boundary = "==Multipart_Boundary_x{$semi_rand}x"; 
 // Add the headers for a file attachment $headers .= "nMIME-Version: 1.0n" . "Content-Type: multipart/mixed;n" . " boundary="{$mime_boundary}""; 

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

  // Add a multipart boundary above the plain message $message = "This is a multi-part message in MIME format.nn" . "--{$mime_boundary}n" . "Content-Type: text/plain; charset="iso-8859-1"n" . "Content-Transfer-Encoding: 7bitnn" . $message . "nn"; 

Теперь, чтобы учесть двоичные типы файлов, нам нужно использовать кодировку Base64 для преобразования (возможно, двоичных) данных вложения файлов в текстовый формат, подходящий для отправки по электронной почте. Все популярные почтовые программы поддерживают кодирование файловых вложений Base64, так что это лучший способ. К счастью, PHP предоставляет функцию для кодирования Base64:

  // Base64 encode the file data $data = chunk_split(base64_encode($data)); 

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

  // Add file attachment to the message $message .= "--{$mime_boundary}n" . "Content-Type: {$fileatt_type};n" . " name="{$fileatt_name}"n" . "Content-Disposition: attachment;n" . " filename="{$fileatt_name}"n" . "Content-Transfer-Encoding: base64nn" . $data . "nn" . "--{$mime_boundary}--n"; } 

Это завершает изменения, необходимые для размещения вложения файла. Теперь мы можем отправить сообщение с быстрым звонком на mail :

 // Send the message $ok = @mail($to, $subject, $message, $headers); if ($ok) { echo "<p>Mail sent! Yay PHP!</p>"; } else { echo "<p>Mail could not be sent. Sorry!</p>"; } ?> 

И вот как мы отправляем электронные письма с вложенными файлами на PHP!

Резюме

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

  • мы узнали, как манипулировать заголовками писем, чтобы играть с получателями писем
  • мы увидели заголовки, которые позволяют отправлять электронную почту в формате HTML
  • мы объединили HTML и текстовые версии письма в одно смешанное сообщение

и наконец…

  • Мы собрали все это вместе с парой новых трюков для отправки сообщений электронной почты с вложенными файлами.

Если у вас возникли проблемы, попробуйте расширить сценарий вложения файлов в этой статье, чтобы разрешить использование нескольких файловых вложений или добавить HTML-сообщение. Если вы объектно-ориентированный тип PHP, попробуйте разработать класс, который включает в себя функциональность, которую мы рассмотрели в этой статье (в Интернете доступно несколько таких сценариев, если вы ищете что-то готовое).

Если вы действительно заинтересованы, ознакомьтесь с RFC для расширений MIME ( RFC 2045 ), чтобы узнать все, на что способна электронная почта, а затем сходите с ума!

Если вам понравилось читать этот пост, вы полюбите Learnable ; место, чтобы узнать новые навыки и приемы у мастеров. Участники получают мгновенный доступ ко всем электронным книгам и интерактивным онлайн-курсам SitePoint, таким как PHP и MySQL для веб-разработчиков для начинающих .