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); ?>