HTML Mail

Headers, HTML Mail and Alternative Parts

HTML mail needs MIME-Version: 1.0 and a Content-Type. HTML alone scores worse with spam filters, so send multipart/alternative: each part starts with -- plus a boundary, --boundary-- ends the body, and clients render the last part they understand, so text goes first.

mail-alt.php: a text part and an HTML part, assembled by handPHP
<?php
declare(strict_types=1);
$b = 'b-' . bin2hex(random_bytes(8));          // boundary: must never occur in the body
$body = "--$b\r\nContent-Type: text/plain; charset=UTF-8\r\n\r\nOrder #1001 confirmed.\r\n"
      . "--$b\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n<h1>Order confirmed</h1>\r\n"
      . "--$b--\r\n";
var_dump(mail('reader@example.com', mb_encode_mimeheader('Order #1001 – confirmed'), $body, [
    'From' => 'orders@example.com', 'MIME-Version' => '1.0',
    'Content-Type' => "multipart/alternative; boundary=\"$b\""]));
Output
$ php -d sendmail_path='docker exec -i mailpit /mailpit sendmail' mail-alt.php
bool(true)
$ curl -s localhost:8019/api/v1/message/latest/headers | jq -r '.Subject[0]'
Order #1001 =?UTF-8?B?4oCTIGNvbmZpcm1lZA==?=

Headers are ASCII only, so mb_encode_mimeheader() made the en dash an RFC 2047 encoded word.