Friday, 3 July 2015

Error with PHP mail(): Multiple or malformed newlines found in additional_header

A new update for PHP has broken a few mailing scripts that a few of our clients use (https://bugs.php.net/bug.php?id=68776)

More specifically, the script sends an email with an attachment - I wrote these using some guides from other sites however it now appears that i've been ill advised as its not technically the correct way to do it.

Original (now broken code) below:

function mail_attachment($filename, $path, $mailto, $from_mail, $from_name, $replyto, $subject, $message) {
    $file = $path.$filename;
    $file_size = filesize($file);
    $handle = fopen($file, "r");
    $content = fread($handle, $file_size);
    fclose($handle);
    $content = chunk_split(base64_encode($content));
    $uid = md5(uniqid(time()));
    $name = basename($file);
    $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/plain; charset=iso-8859-1\r\n";
    $header .= "Content-Transfer-Encoding: 7bit\r\n\r\n";
    $header .= $message."\r\n\r\n";
    $header .= "--".$uid."\r\n";
    $header .= "Content-Type: application/octet-stream; name=\"".$filename."\"\r\n";
    $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."--";
error_reporting(E_ALL);
    if (mail($mailto, $subject, "", $header)) {
        echo "Mail Sent Successfully to " . $mailto ."<br/>"; // or use booleans here
    } else {
        echo "Mail NOT Sent to " .$mailto ."<br/>";
    }

There are now more checks on the header field, which means data which was being stuffed into the header should now really be in the message. See the changes I made to get this working with our webservers (highlighted in yellow):

function mail_attachment($filename, $path, $mailto, $from_mail, $from_name, $replyto, $subject, $message) {
    $file = $path.$filename;
    $file_size = filesize($file);
    $handle = fopen($file, "r");
    $content = fread($handle, $file_size);
    fclose($handle);
    $content = chunk_split(base64_encode($content));
    $uid = md5(uniqid(time()));
    $name = basename($file);
    $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";
(THIS ENTIRE LINE HAS BEEN REMOVED)
    $nmessage = "--".$uid."\r\n";
    $nmessage .= "Content-type:text/plain; charset=iso-8859-1\r\n";
    $nmessage .= "Content-Transfer-Encoding: 7bit\r\n\r\n";
    $nmessage .= $message."\r\n\r\n";
    $nmessage .= "--".$uid."\r\n";
    $nmessage .= "Content-Type: application/octet-stream; name=\"".$filename."\"\r\n"; 
    $nmessage .= "Content-Transfer-Encoding: base64\r\n";
    $nmessage .= "Content-Disposition: attachment; filename=\"".$filename."\"\r\n\r\n";
    $nmessage .= $content."\r\n\r\n";
    $nmessage .= "--".$uid."--";
error_reporting(E_ALL);
    if (mail($mailto, $subject, $nmessage, $header)) {
        echo "Mail Sent Successfully to " . $mailto ."<br/>"; // or use booleans here
    } else {
        echo "Mail NOT Sent to " .$mailto ."<br/>";
    }

}

And that sorted it out - I hope this helps someone as I had a hell of a time trying to work out what the error message meant and its been pretty vague. Add to this the comments on the PHP bug fix page which aren't that helpful and its quite difficult to sort out. Please +1/share this if it helps you so it can help others

21 comments:

  1. Good call - thanks - I added a link from SO page to here..

    ReplyDelete
  2. Thank you - fixed a really old backup script I had!

    ReplyDelete
  3. this saved my bacon! THANKS for posting!!!

    ReplyDelete
  4. Any reason you can think of that gmail webmail can read an attachment but Outlook can't read it? Outlook shows the size as 113b
    Thank you for your time.

    ReplyDelete
  5. I figure out my error. Thanks again the great example!

    ReplyDelete
  6. Thanks, not exactly saved my life but still solved easily my problem after switching PHP versions on the server.

    ReplyDelete
  7. Awesome. Thanks a million - reading your post was like winning Powerball! (considering that our php upgrade caused the emails with attachments to stop working)

    ReplyDelete
  8. thanksmate,
    it helps a lot. Saved my day.

    ReplyDelete
  9. It works with attached inline images too.
    thanks

    ReplyDelete
  10. What about attachments, if want to send any attachments than what will do? Please help me out

    ReplyDelete