Sending email with both HTML, plain text and with attachments

The secret here is that you need two kinds of content-type: multipart/mixed (to separate the message and the attachments) and multipart/alternative (to distinguish HTML and plain text).

Example in PHP below:

<?php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST,OPTIONS');
header('Access-Control-Allow-Headers: accept, content-type');

if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS'){
die('OPTIONS OK');
}

$json = file_get_contents("php://input");

$req = json_decode($json, true);

$from = $req['from'];
$to = $req['to'];
$subject = $req['subject'];
$html = $req['html'];
$text = $req['text'];
$apikey = $req['apikey'];

$attachments = [];

if (array_key_exists('attachments',$req))
{
    $attachments = $req['attachments'];
}

if ($apikey !== 'abc123'){
    http_response_code(401);
    die('API Key ERROR');
}

$boundary = '--'.uniqid('mixed');
$boundaryline = "\r\n--$boundary\r\n";

$boundary_html_text = '--'.uniqid('alt');
$boundary_html_textline = "\r\n--$boundary_html_text\r\n";

$headers = "From: $from" . "\r\n";
$headers .= "X-Mailer: emailapi-PHP/".phpversion()."\r\n";

$headers .= "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: multipart/mixed;boundary=" .'"'. $boundary .'"'. "\r\n";

$message = "This is a MIME encoded message.";

$message .= $boundaryline;
$message .= "Content-Type: multipart/alternative;boundary=" .'"'. $boundary_html_text .'"'. "\r\n";

//Plain text body
$message .= $boundary_html_textline;
$message .= "Content-type: text/plain;charset=utf-8\r\n";
$message .= "Content-Transfer-Encoding: 7bit\r\n";
$message .= "\r\n";
$message .= $text;

//Html body
$message .= $boundary_html_textline;
$message .= "Content-type: text/html;charset=utf-8\r\n";
$message .= "Content-Transfer-Encoding: 7bit\r\n";
$message .= "\r\n";
$message .= $html;

$message .= "\r\n--$boundary_html_text--\r\n";

foreach ($attachments as $attachment) {
        $file_name = $attachment['filename'];
        $encoded_content = $attachment['content.base64'];
        $file_type = 'application/binary';

        $message .= $boundaryline;
        $message .="Content-Type: $file_type; name=".'"'.$file_name.'"'."\r\n";
        $message .="Content-Disposition: attachment; filename=".'"'.$file_name.'"'."\r\n";
        $message .="Content-Transfer-Encoding: base64\r\n";
        $message .="X-Attachment-Id: ".uniqid('', true)."\r\n";
        $message .= "\r\n";
        $message .= chunk_split($encoded_content);
}

$message .= "\r\n--$boundary--\r\n";

$res = @mail($to, $subject, $message, $headers);

header('Content-Type: application/json');

$senddate = date("Y-m-d H:i:s");
$txt = "$senddate: $to - $subject ";
if ($res === true)
{
    $txt .= "[success]";
    echo json_encode(array('result' => 1));
}else{
    $txt .= "[FAILURE]";
    echo json_encode(array('result' => 0));
}


$logfile = file_put_contents('sendlog.txt', $txt.PHP_EOL , FILE_APPEND);

?>