Отправить PHP HTML-почту с вложениями

У меня возникла проблема: до сегодняшнего дня я отправил HTML-письма с PHP, используя заголовок, который содержит

Content-type: text/html;

Теперь я добавил функциональность для добавления вложений. Для этого мне пришлось изменить эту строку на

Content-Type: multipart/mixed;

Теперь, с multipart/mixed, остальная часть почты, поэтому обычный текст отображается так же, как текст /plain. Как я могу понять, что вложения работают, а почтовый текст по-прежнему является HTML?

Ответ 1

Чтобы отправить электронное письмо с вложением, нам нужно использовать тип MIME с множественным или смешанным типом, который указывает, что смешанные типы будут включены в электронную почту. Более того, мы хотим использовать многостраничный/альтернативный тип MIME для отправки как текстовой, так и HTML-версии письма. Посмотрите на пример:

<?php 
//define the receiver of the email 
$to = '[email protected]'; 
//define the subject of the email 
$subject = 'Test email with attachment'; 
//create a boundary string. It must be unique 
//so we use the MD5 algorithm to generate a random hash 
$random_hash = md5(date('r', time())); 
//define the headers we want passed. Note that they are separated with \r\n 
$headers = "From: [email protected]\r\nReply-To: [email protected]"; 
//add boundary string and mime type specification 
$headers .= "\r\nContent-Type: multipart/mixed; boundary=\"PHP-mixed-".$random_hash."\""; 
//read the atachment file contents into a string,
//encode it with MIME base64,
//and split it into smaller chunks
$attachment = chunk_split(base64_encode(file_get_contents('attachment.zip'))); 
//define the body of the message. 
ob_start(); //Turn on output buffering 
?> 
--PHP-mixed-<?php echo $random_hash; ?>  
Content-Type: multipart/alternative; boundary="PHP-alt-<?php echo $random_hash; ?>" 

--PHP-alt-<?php echo $random_hash; ?>  
Content-Type: text/plain; charset="iso-8859-1" 
Content-Transfer-Encoding: 7bit

Hello World!!! 
This is simple text email message. 

--PHP-alt-<?php echo $random_hash; ?>  
Content-Type: text/html; charset="iso-8859-1" 
Content-Transfer-Encoding: 7bit

<h2>Hello World!</h2> 
<p>This is something with <b>HTML</b> formatting.</p> 

--PHP-alt-<?php echo $random_hash; ?>-- 

--PHP-mixed-<?php echo $random_hash; ?>  
Content-Type: application/zip; name="attachment.zip"  
Content-Transfer-Encoding: base64  
Content-Disposition: attachment  

<?php echo $attachment; ?> 
--PHP-mixed-<?php echo $random_hash; ?>-- 

<?php 
//copy current buffer contents into $message variable and delete current output buffer 
$message = ob_get_clean(); 
//send the email 
$mail_sent = @mail( $to, $subject, $message, $headers ); 
//if the message is sent successfully print "Mail sent". Otherwise print "Mail failed" 
echo $mail_sent ? "Mail sent" : "Mail failed"; 
?>

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

Ответ 2

Я пробовал ответить 1 на пару часов без везения. Я нашел решение здесь: http://www.finalwebsites.com/forums/topic/php-e-mail-attachment-script

Работает как чары - менее 5 мин! Возможно, вы захотите изменить (например, я), первый тип содержимого из текста /plain в текст /html.

Вот моя слегка измененная версия для обработки нескольких вложений:

function mail_attachment($files, $path, $mailto, $from_mail, $from_name, $replyto, $subject, $message) {
$uid = md5(uniqid(time()));

$header = "From: ".$from_name." <".$from_mail.">\r\n";
$header .= "Reply-To: ".$replyto."\r\n";
$header .= "MIME-Version: 1.0\r\n";
$header .= "Content-Type: multipart/mixed; boundary=\"".$uid."\"\r\n\r\n";
$header .= "This is a multi-part message in MIME format.\r\n";
$header .= "--".$uid."\r\n";
$header .= "Content-type:text/html; charset=iso-8859-1\r\n";
$header .= "Content-Transfer-Encoding: 7bit\r\n\r\n";
$header .= $message."\r\n\r\n";

    foreach ($files as $filename) { 

        $file = $path.$filename;

        $file_size = filesize($file);
        $handle = fopen($file, "r");
        $content = fread($handle, $file_size);
        fclose($handle);
        $content = chunk_split(base64_encode($content));

        $header .= "--".$uid."\r\n";
        $header .= "Content-Type: application/octet-stream; name=\"".$filename."\"\r\n"; // use different content types here
        $header .= "Content-Transfer-Encoding: base64\r\n";
        $header .= "Content-Disposition: attachment; filename=\"".$filename."\"\r\n\r\n";
        $header .= $content."\r\n\r\n";
    }

$header .= "--".$uid."--";
return mail($mailto, $subject, "", $header);
}

Ответ 3

SWIFTMAIL в php works gr8 для прикрепления с почтой.

Загрузите swiftmailer отсюда http://swiftmailer.org/

Посмотрите на простой код ниже

ВКЛЮЧАТЬ ФАЙЛ

require_once('path/to/swiftMailer/lib/swift_required.php');

СОЗДАТЬ ТРАНСПОРТ

//FOR SMTP
// Create the Transport
$transport = Swift_SmtpTransport::newInstance('smtp.googlemail.com', 465, 'ssl')
    ->setUsername('[email protected]')
    ->setPassword('gmailpassword');

ИЛИ

//FOR NORMAL MAIL
$transport = Swift_MailTransport::newInstance();

ОБЪЕКТ ОБЪЕКТА

// Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance($transport);

СОЗДАТЬ ОБЪЕКТ СООБЩЕНИЯ

$message = Swift_Message::newInstance($subject)
    ->setFrom(array($from => $from))
    ->setTo($to)
    ->setBody($body);
$message->attach(Swift_Attachment::fromPath($filepath));

ОТПРАВИТЬ СООБЩЕНИЕ

$result = $mailer->send($message);

Ответ 4

Если вы действительно хотите узнать, как отформатировать интернет-сообщение, вы должны направить свой запрос на комментарии (также известный как RFC). Тот, который определяет "Многоцелевые расширения электронной почты Интернета - формат интернет-сообщений", RFC2045, выпущенный в ноябре 1996 года.

Формат как-то очень строгий и должен выполняться как есть.

В основном сообщение содержит заголовок и тело. Заголовок определяет тип сообщения, способ его формирования, некоторые другие поля, которые отличаются от одного типа к другому.

Тело образовано разными сущностями. Сущность может быть, например, просто текстовым, например "Hello there!" но также может быть изображением, приложением, что угодно.

ПРИМЕЧАНИЕ В следующих примерах все заключенные в скобки (например, {hello}) должны быть заменены на ваше реальное значение. Любая новая строка на самом деле является CRLF (т.е. ASCII 13 + ASCII 10). Где вы видите два CRLF. Было бы худшим моментом, чтобы показать, насколько вы творчески настроены.

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

MIME-Version: 1.0
To: {[email protected]}
Subject: {email-subject}
X-Priority: {2 (High)}
Content-Type: multipart/mixed; boundary="{mixed-boudary}"

В приведенном выше примере {mixed-boudary} может быть любым уникальным значением хэша, например 000008050800060107020705. Остальные не требуют пояснений.

Теперь, когда мы хотим добавить в сообщение новый объект (например, тело сообщения, изображение, вложение), мы должны сообщить агенту по электронной почте, что новый раздел идет, т.е. для префикса этого объекта значением {mixed-border}. Мы называем это "открываем границу". Обратите внимание, что, открыв границу, мы не вставляем эту границу, как было определено первоначально, мы используем еще два минусовых знака спереди, например - {mixed-boudary}. Когда мы закрываем границу, мы идем аналогично, за исключением того, что в конце мы должны использовать другие 2 минус-знака, например - {mixed-boudary} -

--{mixed-boudary}
the entity content
--{mixed-boudary}--

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

Для содержимого тела HTML заголовок моего объекта будет выглядеть так:

Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: 7bit

поэтому все тело (заключенное в границы) будет выглядеть следующим образом:

--{mixed-boudary}
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: 7bit

<html>
<head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head>
<body bgcolor="#FFFFFF" text="#000000">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque vel 
dapibus arcu. Duis quam dui, ornare non mi nec, luctus faucibus massa. Vivamus 
quis purus in erat euismod ullamcorper vitae eget dolor. Aliquam tempor erat 
accumsan, consectetur ex et, rhoncus risus.
</body>
</html>

Если нужно добавить другой объект, мы будем действовать точно так же, как указано выше. Когда больше нет данных для добавления в сообщение, мы закрываем смешанную границу, т.е. CRLF + - {mixed-boudary} -.

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

Полный пример ниже:

MIME-Version: 1.0
To: {[email protected]}
Subject: {email-subject}
X-Priority: {2 (High)}
Content-Type: multipart/mixed; boundary="{mixed-boudary}"

--{mixed-boudary}
Content-Type: multipart/alternative; boundary="{alternative-boudary}"

--{alternative-boudary}
Content-Type: text/plain; charset=utf-8;
Content-Transfer-Encoding: 7bit

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque vel 
dapibus arcu. Duis quam dui, ornare non mi nec, luctus faucibus massa. Vivamus 
quis purus in erat euismod ullamcorper vitae eget dolor. Aliquam tempor erat 
accumsan, consectetur ex et, rhoncus risus.

--{alternative-boudary}
Content-Type: text/html; charset=utf-8;
Content-Transfer-Encoding: 7bit

<html>
<head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head>
<body bgcolor="#FFFFFF" text="#000000">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque vel 
dapibus arcu. Duis quam dui, ornare non mi nec, luctus faucibus massa. Vivamus 
quis purus in erat euismod ullamcorper vitae eget dolor. Aliquam tempor erat 
accumsan, consectetur ex et, rhoncus risus.
</body>
</html>

--{alternative-boudary}--

--{mixed-boudary}
Content-Type: application/pdf; name="myfile.pdf"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="myfile.pdf"

JVBERi0xLjINOCAwIG9iag08PCAvTGVuZ3RoIDkgMCBSIC9GaWx0ZXIgL0ZsYXRlRGVjb2Rl
ID4+DXN0cmVhbQ1oQ51bbY/cNg7+BfsfhAUO11w3riW/B7gPaZEAAdpcm06RL8EBzoyn68uM
vZ3xZLv//khKsuUxNaMNiiabpUg+pKiHsmxJEcN/UsgiilP4ab2/+XF1I81vszSqclHIOEpj
sdrf/PC2EFVUpmK1vXkZxVKs1uJlJJVYPYrvPra7XVvvxYdIrE7rL83hhVj97+bNyjUoFam7
FnOB+tubGI3FZEkwmhpKXpVRnqJi0PCyjBJ1DjyOYqWBxxXp/1h3X+ov9abZt434pV0feoG/
ars/xU/9/qEZmm7diJ+abmgOr0TGeFNFEuXx5M4B95Idns/QAaJMI1IpKeXi9+ZhaPafm4NQ
cRwzNpK0iirlRvisRBZpVJa+PP51091kkjBWBXrJxUuZRjIXh0Z8FN3MnB5X5st5Kay9355n

--{mixed-boudary}--

СОВЕТЫ

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

@Edit: очень хорошо документированное тематическое исследование + пример PHP можно найти на здесь