Как сделать отправку письма с вложением?

В статье Как сделать отправку письма? рассказывалось об отправке простого текстового письма. Описанные в ней правила следует учитывать и при отпраке письма с вложением. Посмотрим, как можно создать такое письмо.

Прежде всего в заголовках письма с вложением должен быть указан MIME-тип multipart/mixed, например:

MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="::"

Параметр boundary является обязательным и определяет состоящий из символов разделитель, используемый в строке-разделителе для разграничения отдельных частей письма. Значение данного параметра не обязательно заключать в кавычки, но если этого не сделать, то, например, знак двоеточия в разделителе использовать уже будет нельзя. В строке-разделителе должны находиться два дефиса перед значением разделителя, а в последней такой строке – еще и два дефиса после значения разделителя. Необходимо выбирать такой разделитель, при котором строка-разделитель не присутствовала ни в одной части письма. Чтобы не тратить ресурсы на формирование разделителя, удовлетворяющего данному условию, можно кодировать все части письма в кодировке Base64, в алфавите которой отсутствует символ дефис. При этом добавлять дефисы в сам разделитель не требуется, потому что они входят в состав строки-разделителя.

Полный текст письма с одним вложением имеет следующий формат:

Пролог
--разделитель
Заголовки текстовой части письма

Содержимое текстовой части письма
--разделитель
Заголовки вложения

Содержимое вложения
--разделитель--
Эпилог

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

Пролог и эпилог обычно представляют собой небольшие пояснительные тексты в кодировке US-ASCII для получателей, использующих устаревшие почтовые клиенты, не поддерживающие письма с вложениями. Пролог или эпилог могут отсутствовать, однако строки-разделители, которыми они отделяются от других частей письма, должны присутствовать обязательно. Эпилог часто отсутствует. Если пролог или эпилог отсутствуют, то могут отсутствовать и соответствующие разделители строк "\r\n" после пустого пролога или перед пустым эпилогом.

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

Пример типичного набора заголовков текстовой части письма:

Content-Transfer-Encoding: base64
Content-Type: text/plain; charset=utf-8

Пример типичного набора заголовков вложения:

Content-Transfer-Encoding: base64
Content-Type: text/plain; name="file.txt"
Content-Disposition: attachment; filename="file.txt"

Использование в заголовке вложения Content-Type параметра name с исходным (рекомендуемым) именем файла вместо параметра charset, определяющего символьную кодировку содержимого, связано с тем, что клиент прежде всего должен предоставлять пользователю возможность сохранения вложения в виде файла, а не отображать его содержимое. Такая подмена параметра, вероятно, обусловлена тем, что исторически заголовок Content-Type появился раньше заголовка Content-Disposition, явно определяющего, должно ли отображаться содержимое вложения. Этим же, вероятно, обусловлено и дублирование имени файла в заголовках.

Для отображения содержимого вложения в «основном потоке» нужно указать в заголовке Content-Disposition значение inline вместо значения attachment, при этом также можно использовать параметр filename.

В текстовой части письма можно использовать не только тип text/plain, но и тип text/html, как это было описано для простого текстового письма. Более того, для совместимости можно объединить обе текстовые версии с помощью контейнера типа multipart/alternative, размещенного в текстовой части письма. Заголовок и содержимое контейнера данного типа имеют формат, аналогичный описанному выше (версия типа text/plain как более простая в плане совместимости должна располагаться первой):

--разделитель-1
Content-Type: multipart/alternative; boundary="разделитель-2"

--разделитель-2
Заголовки первой версии

Содержимое первой версии
--разделитель-2
Заголовки второй версии

Содержимое второй версии
--разделитель-2--
--разделитель-1

Строки-разделители внешнего контейнера добавлены для большей наглядности.

Попробуйте выполнить следующий код, предварительно сохранив его в файле в кодировке UTF-8 с указанием корректного значения $to:

<?php

$to='user@example.com';
$subject='=?utf-8?B?'.base64_encode('Письмо с вложением').'?=';
$message='--::'."\r\n".
         'Content-Transfer-Encoding: base64'."\r\n".
         'Content-Type: text/plain; charset=utf-8'."\r\n".
         "\r\n".
         chunk_split(base64_encode('Файл прилагается!'))."\r\n".
         '--::'."\r\n".
         'Content-Transfer-Encoding: base64'."\r\n".
         'Content-Type: text/plain; name="file.txt"'."\r\n".
         'Content-Disposition: attachment; filename="file.txt"'."\r\n".
         "\r\n".
         chunk_split(base64_encode('Hello world!'))."\r\n".
         '--::--';
$headers='MIME-Version: 1.0'."\r\n".
         'Content-Type: multipart/mixed; boundary="::"';

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

?>Done

После результата, возвращаемого функцией chunk_split, нет необходимости добавлять разделитель строк \r\n, т.к. функция добавляет разделитель строк непосредственно в конец результата. Однако при кодировании содержимого письма или отдельной его части в кодировке Base64 после кода содержимого вполне допустимо наличие дополнительных разделителей строк.

Комментарии: 0

Отправить комментарий

Ваш адрес E-mail не будет опубликован.