Ok, I'm seriously stuck on this despite having previously asked a related question and having worked on this all morning.
The problem is basic - I cannot send email using PHP from a new app I'm starting. The mailhost is localhost and it does not require authentication. I can checkout a previous app I wrote that also uses the PHP mail function and it works. The php.ini file is the same in both cases, and both cases therefore use localhost.
Both the working app and the new app both have swiftmailer installed using composer, but in both the working example and in this example swiftmailer is not used.
Here is the actual code I want to work:
// Determine headers
$uid = md5(uniqid(time()));
$headers = "From: " . $this->fromAddress . " <" . $this->fromName . ">\r\n";
$headers.= "Reply-To: " . $this->fromAddress . " <" . $this->fromName . ">\r\n";
if ($this->cc != "") { $headers .= "CC: ".$this->cc."\r\n"; }
if ($this->bcc != "") { $headers .= "BCC: ".$this->bcc."\r\n"; }
$headers .= "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: multipart/mixed; boundary=\"" . $uid . "\"\r\n\r\n";
$headers .= "This is a multi-part message in MIME format.\r\n";
$headers .= "--" . $uid . "\r\n";
$headers .= "Content-type:text/html; charset=iso-8859-1\r\n";
$headers .= "Content-Transfer-Encoding: 7bit\r\n\r\n";
$headers .= $this->body . "\r\n\r\n";
// Optionally attach a file
foreach ($this->attachments as $attachment) {
$fileName = basename($attachment);
$fileSize = filesize($attachment);
$handle = fopen($attachment, "r");
$content = fread($handle, $fileSize);
fclose($handle);
$content = chunk_split(base64_encode($content));
$headers .= "--" . $uid . "\r\n";
$headers .= "Content-Type: application/octet-stream; name=\"" . $fileName . "\"\r\n";
$headers .= "Content-Transfer-Encoding: base64\r\n";
$headers .= "Content-Disposition: attachment; filename=\"" . $fileName . "\"\r\n\r\n";
$headers .= $content."\r\n\r\n";
unlink($attachment);
}
// Conclude headers
$headers .= "--".$uid."--";
// Send the email
$mail_sent = mail($this->toAddress,$this->subject,'',$headers);
if (!$mail_sent) {
throw new Exception('Email failed to send');
}
This code throws the exception, "Email failed to send". I can confirm that $this->toAddress is a valid email address and that $this->subject is a valid subject, and that $this->fromAddress is a valid email address, and that $this->body is a valid body, only a few characters long.
In attempting to boil this down to the simplest example, I tried the following code:
<?php
// The message
$message = "Line 1\r\nLine 2\r\nLine 3";
// In case any of our lines are larger than 70 characters, we should use wordwrap()
$message = wordwrap($message, 70, "\r\n");
// Send
$result = mail('lowens#mycompany.com', 'My Subject', $message);
if (!$result) {
error_log("fail");
}
?>
That logs "fail".
Just to confirm that localhost works, I re-checked out code that works. Here's the code that works:
// Determine headers
$uid = md5(uniqid(time()));
$headers= "From: " . $login->getUser() . " <" . $login->getUserEmail() . ">\r\n";
$headers.= "Reply-To: " . $login->getUser() . " <" . $login->getUserEmail() . ">\r\n";
if ($bcc != "") { $headers .= "BCC: ".$bcc."\r\n"; }
$headers .= "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: multipart/mixed; boundary=\"".$uid."\"\r\n\r\n";
$headers .= "This is a multi-part message in MIME format.\r\n";
$headers .= "--".$uid."\r\n";
$headers .= "Content-type:text/html; charset=iso-8859-1\r\n";
$headers .= "Content-Transfer-Encoding: 7bit\r\n\r\n";
$headers .= $message."\r\n\r\n";
// Optionally attach a file
foreach ($attachedFilePaths as $attachedFilePath) {
$fileName = basename($attachedFilePath);
$fileSize = filesize($attachedFilePath);
$handle = fopen($attachedFilePath, "r");
$content = fread($handle, $fileSize);
fclose($handle);
$content = chunk_split(base64_encode($content));
$headers .= "--".$uid."\r\n";
$headers .= "Content-Type: application/octet-stream; name=\"".$fileName."\"\r\n"; // use different content types here
$headers .= "Content-Transfer-Encoding: base64\r\n";
$headers .= "Content-Disposition: attachment; filename=\"".$fileName."\"\r\n\r\n";
$headers .= $content."\r\n\r\n";
unlink($attachedFilePath);
}
$headers .= "--".$uid."--";
// Send the email
$mail_sent = #mail($toAddr,$subject,'',$headers);
// Save this email as a task
require_once('../classes/task.class.php');
$task = new Task();
$task->saveMailAsTask($CustomerId, $toAddr, $bcc, $subject, $message);
// This can be used to return a success or failure
if ($mail_sent) {
redirect("http://$domainName/admin/index.php?task=account&event=viewdetails&id=$CustomerId&emailSentOK=true&d=emailResponse");
} else {
redirect("http://$domainName/admin/index.php?task=account&event=viewdetails&id=$CustomerId&emailSentOK=false&d=emailResponse");
}
I have eliminated the mailhost (localhost) as the cause of the problem, and the PHP.ini file. The only other two sources of the problem I would suppose are in the code itself and in an unknown cause that I am ignorant of. The code looks fine to me...
What gives? And why the heck can't a decent error message come out of mail()?
Some things to check:
In your php.ini ensure that sendmail_path is set to the output of
which sendmail
and then set accordingly if not:
sendmail_path = '/usr/sbin/sendmail -t'
Try send a message with sendmail and make sure you are not blacklisted:
sendmail -v someone#someaddress.com "hello"
(CTR+D will send and you can see the response from the receiving server)
The problem was the from field. I was inverting the order of the name and address.
INCORRECT:
$headers = "From: " . $this->fromAddress . " <" . $this->fromName . ">\r\n";
$headers.= "Reply-To: " . $this->fromAddress . " <" . $this->fromName . ">\r\n";
CORRECT:
$headers = "From: " . $this->fromName . " <" . $this->fromAddress . ">\r\n";
$headers.= "Reply-To: " . $this->fromName . " <" . $this->fromAddress . ">\r\n";
Related
Suddenly have started receiving the above error without any changes having been made to the script.
Host is 1and1 (I know...)
The script still works fine on a different server, and so my suspicion is that there must have been some server config change that has lead to this, although the hosts plead ignorance.
There's no information on the above error at all in Google that I can find - does anybody have any ideas? Server is running Apache if that helps.
Had just the similar problem.
It came out of the blue. No PHP Code was changed.
What was changed: PHP was upgraded 5.5.25-1 to 5.5.26.
A security risk in PHP mail() function has been fixed and extra newlines in additional_headers are allowed no more. Because extra newlines mean: now starts the email message (and we surely don't want somebody to inject some newlines through headers followed by an evil message).
What previously have worked fine, e.g. just having extra newlines after headers or even passing the whole message to additional_headers, will function no more.
Solution:
Sanitize your headers. No multiple newlines in additional_headers argument. These count as "multiple or malformed newlines": \r\r, \r\0, \r\n\r\n, \n\n, \n\0.
Use additional_headers for headers only. Email message (multipart or not, with ir without attachments, etc) belongs in message argument, not in headers.
PHP Security Bug report: https://bugs.php.net/bug.php?id=68776
C Code diff how its fixed: http://git.php.net/?p=php-src.git;a=blobdiff;f=ext/standard/mail.c;h=448013a472a3466245e64b1cb37a9d1b0f7c007e;hp=1ebc8fecb7ef4c266a341cdc701f0686d6482242;hb=9d168b863e007c4e15ebe4d2eecabdf8b0582e30;hpb=eee8b6c33fc968ef8c496db8fb54e8c9d9d5a8f9
None of the above answers solved this problem for me. So, I expanded my search to "mail with attachment and HTML message issues." Piecing together info from a few different posts, I came up with this. It allows for BOTH HTML email and an attachment.
My original header code:
$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";
$header .= "--".$uid."\r\n";
$header .= "Content-Type: text/html; charset=ISO-8859-1\r\n";
$header .= "Content-Transfer-Encoding: 8bit\r\n";
$header .= $body."\r\n";
$header .= "--".$uid."\r\n";
$header .= "Content-Type: application/pdf; name=\"".$filename."\"\r\n";
$header .= "Content-Transfer-Encoding: base64\r\n";
$header .= "Content-Disposition: attachment; filename=\"".$filename."\"\r\n";
$header .= $content."\r\n";
$header .= "--".$uid."--";
if (mail($mail_to, $subject, "", $header))
{
return "mail_success";
}
else
{
return "mail_error";
}
My new code (complete):
Note that $body is the HTML that is being assembled by a different function.
$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);
$eol = PHP_EOL;
// Basic headers
$header = "From: ".$from_name." <".$from_mail.">".$eol;
$header .= "Reply-To: ".$replyto.$eol;
$header .= "MIME-Version: 1.0\r\n";
$header .= "Content-Type: multipart/mixed; boundary=\"".$uid."\"";
// Put everything else in $message
$message = "--".$uid.$eol;
$message .= "Content-Type: text/html; charset=ISO-8859-1".$eol;
$message .= "Content-Transfer-Encoding: 8bit".$eol.$eol;
$message .= $body.$eol;
$message .= "--".$uid.$eol;
$message .= "Content-Type: application/pdf; name=\"".$filename."\"".$eol;
$message .= "Content-Transfer-Encoding: base64".$eol;
$message .= "Content-Disposition: attachment; filename=\"".$filename."\"".$eol;
$message .= $content.$eol;
$message .= "--".$uid."--";
if (mail($mail_to, $subject, $message, $header))
{
return "mail_success";
}
else
{
return "mail_error";
}
Two key changes here. (1) removed all the multi-part stuff from the headers into $message. (2) removed all the "\r\n" stuff and added $eol = PHP_EOL; to the code.
Together, these changes allowed me to once again send HTML email with attachments.
Had the same problem:
Removed the mime boundary and message from the header and all worked.
$header = "From: ".$from_name." <".$from_mail.">\n";
$header .= "Reply-To: ".$replyto."\n";
$header .= "MIME-Version: 1.0\n";
$header .= "Content-Type: multipart/mixed; boundary=\"".$uid."\"\n\n";
$emessage= "--".$uid."\n";
$emessage.= "Content-type:text/plain; charset=iso-8859-1\n";
$emessage.= "Content-Transfer-Encoding: 7bit\n\n";
$emessage .= $message."\n\n";
$emessage.= "--".$uid."\n";
$emessage .= "Content-Type: application/octet-stream; name=\"".$filename."\"\n"; // use different content types here
$emessage .= "Content-Transfer-Encoding: base64\n";
$emessage .= "Content-Disposition: attachment; filename=\"".$filename."\"\n\n";
$emessage .= $content."\n\n";
$emessage .= "--".$uid."--";
mail($mailto,$subject,$emessage,$header);
None of the above fixed it for me - main issue is you must not put anything other than header definitions in headers. Old scripts bunged anything in there. So move any text or attachments that were stuffed in to headers into the message body. Makes sense..
This has an explanation
(I guess it's same solution as Frank's above plus Davisca's "no double new lines" - but you need doubled new lines for attachments)
This will solve your problem. I have changed a little bit of Frank's code. This code will support attachment and html.
<?php
$filename = "certificate.jpg";
$path = "/home/omnibl/subdomains/test/certificate/certimage/";
$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);
$eol = PHP_EOL;
$subject = "Mail Out Certificate";
$message = '<h1>Hi i m mashpy</h1>';
$from_name = "mail#example.com";
$from_mail = "mail#example.com";
$replyto = "mail#example.com";
$mailto = "mail#example.com";
$header = "From: " . $from_name . " <" . $from_mail . ">\n";
$header .= "Reply-To: " . $replyto . "\n";
$header .= "MIME-Version: 1.0\n";
$header .= "Content-Type: multipart/mixed; boundary=\"" . $uid . "\"\n\n";
$emessage = "--" . $uid . "\n";
$emessage .= "Content-type:text/html; charset=iso-8859-1\n";
$emessage .= "Content-Transfer-Encoding: 7bit\n\n";
$emessage .= $message . "\n\n";
$emessage .= "--" . $uid . "\n";
$emessage .= "Content-Type: application/octet-stream; name=\"" . $filename . "\"\n"; // use different content types here
$emessage .= "Content-Transfer-Encoding: base64\n";
$emessage .= "Content-Disposition: attachment; filename=\"" . $filename . "\"\n\n";
$emessage .= $content . "\n\n";
$emessage .= "--" . $uid . "--";
mail($mailto, $subject, $emessage, $header);
Another scenario that brings the same new error is if you are not sending any headers to the "mail" command. It used to just use a default, and now gives the misleading error: "Multiple or malformed newlines found in additional_header".
Can be fixed by adding this:
$header = "From: ".$from_name." <".$from_mail.">\n";
$header .= "Reply-To: ".$replyto."\n";
$header .= "MIME-Version: 1.0\n";
...
mail($mailto,$subject,$emessage,$header);
my PHP version - 5.4.43,
probably contains Fixed bug #68776.
googling to the same error showed [http://fossies.org/diffs/php/5.4.42_vs_5.4.43/ext/standard/mail.c-diff.html]
=> I cannot use empty strings as mail() parameters.
my old code:
$headers = 'From: ' . $frm . "\r\n";
$headers .= 'To: ' . $contactEmail . "\r\n";
if ( $flag ) {
$headers .= 'To: ' . $contactEmail2 . "\r\n";
}
$headers .= 'Cc: ' . $contactEmailCc . "\r\n";
$headers .= 'Bcc: ' . $contactEmailBcc . "\r\n";
$headers .= 'Return-Path: ' . $frm . "\r\n";
$headers .= 'MIME-Version: 1.0' ."\r\n";
$headers .= 'Content-Type: text/HTML; charset=ISO-8859-1' . "\r\n";
$headers .= 'Content-Transfer-Encoding: 8bit'. "\n\r\n";
$headers .= $htmlText . "\r\n";
if (!mail('', $strSubject, '', $headers)) { // !!! note the empty parameters.
my new code:
$headers = 'From: ' . $frm . "\r\n";
// note: no "To: " !!!
$headers .= 'Cc: ' . $contactEmailCc . "\r\n";
$headers .= 'Bcc: ' . $contactEmailBcc . "\r\n";
$headers .= 'Return-Path: ' . $frm . "\r\n";
$headers .= 'MIME-Version: 1.0' ."\r\n";
$headers .= 'Content-Type: text/HTML; charset=ISO-8859-1' . "\r\n";
$headers .= 'Content-Transfer-Encoding: 8bit'. "\n\r\n";
// note: no $htmlText !!!
// note: new parameters:
$mTo = $contactEmail;
if ( $flag ) {
$mTo .= ', ' . $contactEmail2;
}
$mMessage .= $htmlText . "\r\n";
if (!mail($mTo, $strSubject, $mMessage, $headers)) {
You may be running into Bug #69874 Can't set empty additional_headers for mail() if you haven't done anything stupid (i.e. forgot to sanitize the headers).
Test for the bug
$ php -d display_errors=1 -d display_startup_errors=1 -d error_reporting=30719 -r 'mail("test#email.com","Subject Here", "Message Here",NULL);'
Warning: mail(): Multiple or malformed newlines found in additional_header in Command line code on line 1
Alternately if you know your PHP version (hint: php -v) you can check the changelog for the bug number (69874) to see whether the fix has been applied for your version.
A short-term fix is to replace calls to mail() like this
function fix_mail( $to , $subject , $message , $additional_headers =NULL, $additional_parameters=NULL ) {
$to=filter_var($to, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES| FILTER_FLAG_STRIP_LOW| FILTER_FLAG_STRIP_HIGH);
$subject=filter_var($subject, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES| FILTER_FLAG_STRIP_LOW| FILTER_FLAG_STRIP_HIGH);
if (!$additional_headers)
return mail( $to , $subject , $message );
if (!$additional_parameters)
return mail( $to , $subject , $message , $additional_headers );
return mail( $to , $subject , $message , $additional_headers, $additional_parameters );
}
Incase this helps anyone, I am using PHP 5.6 and an old code igniter v1 email library
email.php: line 1510 - I've added this:
$this->_header_str = str_replace("\r\r","",$this->_header_str);
$this->_header_str = str_replace("\r\0","",$this->_header_str);
$this->_header_str = str_replace("\r\n\r\n","",$this->_header_str);
$this->_header_str = str_replace("\n\n","",$this->_header_str);
$this->_header_str = str_replace("\n\0","",$this->_header_str);
above this line:
if ( ! mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str, "-f ".$this->clean_email($this->_headers['Return-Path'])))
return FALSE;
else
return TRUE;
And that is successfully sanitising the email headers and resolving the error that I was receiving (same as the original poster of this question)
This is quite possibly someone trying to take advantage of your code to inject email headers.
http://resources.infosecinstitute.com/email-injection/
I would suggest you examine access logs etc and look for unusual activity. The fact you are getting error messages hopefully means that your script has not been compromised and it is erroring out instead. You need to make sure though.
I try to add send email attachment using php,file attachment working fine but attachment file open blank document.How to solve this issue.Below mentioned my code.
$from_email = 'sender_mail#example.com'; //sender email
$recipient_email = 'manosk24#gmail.com'; //recipient email
$subject = 'Test mail'; //subject of email
$message = 'This is body of the message'; //message body
$filename = "file1.pdf";
$path = $_SERVER['DOCUMENT_ROOT'] . "/mail-function/upload/";
$file = $path.$filename;
$file_size = filesize($file);
$handle = fopen($file, "rb");
$content = fread($handle, $file_size);
fclose($handle);
$content = chunk_split(base64_encode($content));
$boundary = md5(uniqid(time()));
//header
$headers = "MIME-Version: 1.0\r\n";
$headers .= "From:" . $from_email . "\r\n";
$headers .= "Reply-To: " . $user_email . "" . "\r\n";
$headers .= "Content-Type: multipart/mixed; boundary = $boundary\r\n\r\n";
//plain text
$body = "--$boundary\r\n";
$body .= "Content-Type: text/plain; charset=ISO-8859-1\r\n";
$body .= "Content-Transfer-Encoding: base64\r\n\r\n";
$body .= chunk_split(base64_encode($message));
//attachment
$body .= "--$boundary\r\n";
$body .="Content-Type: application/pdf; name=" . $filename . "\r\n";
$body .="Content-Disposition: attachment; filename=" . $filename . "\r\n";
$body .="Content-Transfer-Encoding: base64\r\n";
$body .="X-Attachment-Id: " . rand(1000, 99999) . "\r\n\r\n";
$body .= $encoded_content;
$sentMail = #mail($recipient_email, $subject, $body, $headers);
if ($sentMail) { //output success or failure messages
die('Thank you for your email');
} else {
die('Could not send mail! Please check your PHP mail configuration.');
}
Sorry for my spelling mistake..
try this code,
$filename = "file1.pdf";
$file = $path . "/" . $filename;
$message ="my message";
$file_size = filesize($file);
$handle = fopen($file, "r");
$content = fread($handle, $file_size);
fclose($handle);
$content = chunk_split(base64_encode($content));
// a random hash will be necessary to send mixed content
$separator = md5(time());
// carriage return type (we use a PHP end of line constant)
$eol = PHP_EOL;
// main header (multipart mandatory)
$headers = "From: name <test#test.com>" . $eol;
$headers .= "MIME-Version: 1.0" . $eol;
$headers .= "Content-Type: multipart/mixed; boundary=\"" . $separator . "\"" . $eol;
$headers .= "Content-Transfer-Encoding: 7bit" . $eol;
$headers .= "This is a MIME encoded message." . $eol;
// message
$headers .= "--" . $separator . $eol;
$headers .= "Content-Type: text/plain; charset=\"iso-8859-1\"" . $eol;
$headers .= "Content-Transfer-Encoding: 8bit" . $eol;
$headers .= $message . $eol;
// attachment
$headers .= "--" . $separator . $eol;
$headers .= "Content-Type: application/octet-stream; name=\"" . $filename . "\"" . $eol;
$headers .= "Content-Transfer-Encoding: base64" . $eol;
$headers .= "Content-Disposition: attachment" . $eol;
$headers .= $content . $eol;
$headers .= "--" . $separator . "--";
//SEND Mail
if (mail($mailto, $subject, "", $headers)) {
echo "mail send ... OK"; // or use booleans here
} else {
echo "mail send ... ERROR!";
}
i hope it will be helpful.
I've got this little bump...
I'm trying to send bcc copies but when I increase the number of headers the attached files are sent as the images code.
Here is my code:
$to="name#extension.com";
$subject="Petición de financiamiento";
$from = stripslashes($_POST['nombre'])."<".stripslashes($_POST['correo']).">";
$mime_boundary="==Multipart_Boundary_x".md5(mt_rand())."x";
$headers = "From: $from\r\n" .
"MIME-Version: 1.0\r\n" .
"Content-Type: multipart/mixed;\r\n" .
" boundary=\"{$mime_boundary}\"";
$message="Petición de financiamiento\r\n";
$message .="\r\n";
$message .= "Nombre: ".$_POST["nombre"]."\r\n";
$message .= "Correo: ".$_POST["correo"]."\r\n";
$message .= "Teléfono: ".$_POST["telef"]."\r\n";
$message .="\r\n";
$message .="\r\n";
$message .= $_POST["mensaje"];
$message .="\r\n";
$message .="\r\n";
$message = "This is a multi-part message in MIME format.\n\n" .
"--{$mime_boundary}\n" .
"Content-Type: text/plain; charset=\"iso-8859-1\"\n" .
"Content-Transfer-Encoding: 7bit\n\n" .
$message . "\n\n";
foreach($_FILES as $userfile){
$tmp_name = $userfile['tmp_name'];
$type = $userfile['type'];
$name = $userfile['name'];
$size = $userfile['size'];
if (file_exists($tmp_name)){
if(is_uploaded_file($tmp_name)){
$file = fopen($tmp_name,'rb');
$data = fread($file,filesize($tmp_name));
fclose($file);
$data = chunk_split(base64_encode($data));
}
$message .= "--{$mime_boundary}\n" .
"Content-Type: {$type};\n" .
" name=\"{$name}\"\n" .
"Content-Disposition: attachment;\n" .
" filename=\"{$fileatt_name}\"\n" .
"Content-Transfer-Encoding: base64\n\n" .
$data . "\n\n";
}
}
$message.="--{$mime_boundary}--\n";
$message.="--{$mime_boundary}--\n";
if (#mail($to, $subject, $message, $headers))
echo "Mensaje enviado";
else
echo "No se pudo enviar";
Any Idea how to add the BCC's, thank you in advance for any help.
Just put $headers .= "Bcc: $emailadress\r\n"; say after the Content-type line
that should work i guess.
$headers = "From: $from\r\n" .
"MIME-Version: 1.0\r\n" .
"Content-Type: multipart/mixed;\r\n" .
" boundary=\"{$mime_boundary}\"";
On your headers just add this line
$headers.= "Bcc: email#example.com" . "\r\n";
Check the php mail function
http://php.net/manual/en/function.mail.php
[Edited to fit the 'real' solution Sam Ram San have found by himself]
A nice, clear and expandable way to manage headers (including bcc):
$headers = array();
$headers[] = "MIME-Version: 1.0";
$headers[] = "Content-type: text/plain; charset=iso-8859-1";
$headers[] = "From: $from";
$headers[] = "Bcc: $bcc_address1,$bcc_address2,$bcc_address3";
// and so on...
mail($to, $subject, $email, implode("\r\n", $headers));
Using this you avoid including unwanted blank spaces in front of the header field names ("Bcc" -> correct. " Bcc" -> incorrect)
Edited: as a general rule when sending emails, multiple addresses (in from, cc, bcc, cco... fields) should be separated using commas sign (","). I.e: $bcc="john#doe.com,james#doe.org,lucy#doe.com"
All I needed to do was to use a csv on the:
$to="name#extension.com,mail2#bla.com";
Thank You guys.
Suddenly have started receiving the above error without any changes having been made to the script.
Host is 1and1 (I know...)
The script still works fine on a different server, and so my suspicion is that there must have been some server config change that has lead to this, although the hosts plead ignorance.
There's no information on the above error at all in Google that I can find - does anybody have any ideas? Server is running Apache if that helps.
Had just the similar problem.
It came out of the blue. No PHP Code was changed.
What was changed: PHP was upgraded 5.5.25-1 to 5.5.26.
A security risk in PHP mail() function has been fixed and extra newlines in additional_headers are allowed no more. Because extra newlines mean: now starts the email message (and we surely don't want somebody to inject some newlines through headers followed by an evil message).
What previously have worked fine, e.g. just having extra newlines after headers or even passing the whole message to additional_headers, will function no more.
Solution:
Sanitize your headers. No multiple newlines in additional_headers argument. These count as "multiple or malformed newlines": \r\r, \r\0, \r\n\r\n, \n\n, \n\0.
Use additional_headers for headers only. Email message (multipart or not, with ir without attachments, etc) belongs in message argument, not in headers.
PHP Security Bug report: https://bugs.php.net/bug.php?id=68776
C Code diff how its fixed: http://git.php.net/?p=php-src.git;a=blobdiff;f=ext/standard/mail.c;h=448013a472a3466245e64b1cb37a9d1b0f7c007e;hp=1ebc8fecb7ef4c266a341cdc701f0686d6482242;hb=9d168b863e007c4e15ebe4d2eecabdf8b0582e30;hpb=eee8b6c33fc968ef8c496db8fb54e8c9d9d5a8f9
None of the above answers solved this problem for me. So, I expanded my search to "mail with attachment and HTML message issues." Piecing together info from a few different posts, I came up with this. It allows for BOTH HTML email and an attachment.
My original header code:
$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";
$header .= "--".$uid."\r\n";
$header .= "Content-Type: text/html; charset=ISO-8859-1\r\n";
$header .= "Content-Transfer-Encoding: 8bit\r\n";
$header .= $body."\r\n";
$header .= "--".$uid."\r\n";
$header .= "Content-Type: application/pdf; name=\"".$filename."\"\r\n";
$header .= "Content-Transfer-Encoding: base64\r\n";
$header .= "Content-Disposition: attachment; filename=\"".$filename."\"\r\n";
$header .= $content."\r\n";
$header .= "--".$uid."--";
if (mail($mail_to, $subject, "", $header))
{
return "mail_success";
}
else
{
return "mail_error";
}
My new code (complete):
Note that $body is the HTML that is being assembled by a different function.
$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);
$eol = PHP_EOL;
// Basic headers
$header = "From: ".$from_name." <".$from_mail.">".$eol;
$header .= "Reply-To: ".$replyto.$eol;
$header .= "MIME-Version: 1.0\r\n";
$header .= "Content-Type: multipart/mixed; boundary=\"".$uid."\"";
// Put everything else in $message
$message = "--".$uid.$eol;
$message .= "Content-Type: text/html; charset=ISO-8859-1".$eol;
$message .= "Content-Transfer-Encoding: 8bit".$eol.$eol;
$message .= $body.$eol;
$message .= "--".$uid.$eol;
$message .= "Content-Type: application/pdf; name=\"".$filename."\"".$eol;
$message .= "Content-Transfer-Encoding: base64".$eol;
$message .= "Content-Disposition: attachment; filename=\"".$filename."\"".$eol;
$message .= $content.$eol;
$message .= "--".$uid."--";
if (mail($mail_to, $subject, $message, $header))
{
return "mail_success";
}
else
{
return "mail_error";
}
Two key changes here. (1) removed all the multi-part stuff from the headers into $message. (2) removed all the "\r\n" stuff and added $eol = PHP_EOL; to the code.
Together, these changes allowed me to once again send HTML email with attachments.
Had the same problem:
Removed the mime boundary and message from the header and all worked.
$header = "From: ".$from_name." <".$from_mail.">\n";
$header .= "Reply-To: ".$replyto."\n";
$header .= "MIME-Version: 1.0\n";
$header .= "Content-Type: multipart/mixed; boundary=\"".$uid."\"\n\n";
$emessage= "--".$uid."\n";
$emessage.= "Content-type:text/plain; charset=iso-8859-1\n";
$emessage.= "Content-Transfer-Encoding: 7bit\n\n";
$emessage .= $message."\n\n";
$emessage.= "--".$uid."\n";
$emessage .= "Content-Type: application/octet-stream; name=\"".$filename."\"\n"; // use different content types here
$emessage .= "Content-Transfer-Encoding: base64\n";
$emessage .= "Content-Disposition: attachment; filename=\"".$filename."\"\n\n";
$emessage .= $content."\n\n";
$emessage .= "--".$uid."--";
mail($mailto,$subject,$emessage,$header);
None of the above fixed it for me - main issue is you must not put anything other than header definitions in headers. Old scripts bunged anything in there. So move any text or attachments that were stuffed in to headers into the message body. Makes sense..
This has an explanation
(I guess it's same solution as Frank's above plus Davisca's "no double new lines" - but you need doubled new lines for attachments)
This will solve your problem. I have changed a little bit of Frank's code. This code will support attachment and html.
<?php
$filename = "certificate.jpg";
$path = "/home/omnibl/subdomains/test/certificate/certimage/";
$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);
$eol = PHP_EOL;
$subject = "Mail Out Certificate";
$message = '<h1>Hi i m mashpy</h1>';
$from_name = "mail#example.com";
$from_mail = "mail#example.com";
$replyto = "mail#example.com";
$mailto = "mail#example.com";
$header = "From: " . $from_name . " <" . $from_mail . ">\n";
$header .= "Reply-To: " . $replyto . "\n";
$header .= "MIME-Version: 1.0\n";
$header .= "Content-Type: multipart/mixed; boundary=\"" . $uid . "\"\n\n";
$emessage = "--" . $uid . "\n";
$emessage .= "Content-type:text/html; charset=iso-8859-1\n";
$emessage .= "Content-Transfer-Encoding: 7bit\n\n";
$emessage .= $message . "\n\n";
$emessage .= "--" . $uid . "\n";
$emessage .= "Content-Type: application/octet-stream; name=\"" . $filename . "\"\n"; // use different content types here
$emessage .= "Content-Transfer-Encoding: base64\n";
$emessage .= "Content-Disposition: attachment; filename=\"" . $filename . "\"\n\n";
$emessage .= $content . "\n\n";
$emessage .= "--" . $uid . "--";
mail($mailto, $subject, $emessage, $header);
Another scenario that brings the same new error is if you are not sending any headers to the "mail" command. It used to just use a default, and now gives the misleading error: "Multiple or malformed newlines found in additional_header".
Can be fixed by adding this:
$header = "From: ".$from_name." <".$from_mail.">\n";
$header .= "Reply-To: ".$replyto."\n";
$header .= "MIME-Version: 1.0\n";
...
mail($mailto,$subject,$emessage,$header);
my PHP version - 5.4.43,
probably contains Fixed bug #68776.
googling to the same error showed [http://fossies.org/diffs/php/5.4.42_vs_5.4.43/ext/standard/mail.c-diff.html]
=> I cannot use empty strings as mail() parameters.
my old code:
$headers = 'From: ' . $frm . "\r\n";
$headers .= 'To: ' . $contactEmail . "\r\n";
if ( $flag ) {
$headers .= 'To: ' . $contactEmail2 . "\r\n";
}
$headers .= 'Cc: ' . $contactEmailCc . "\r\n";
$headers .= 'Bcc: ' . $contactEmailBcc . "\r\n";
$headers .= 'Return-Path: ' . $frm . "\r\n";
$headers .= 'MIME-Version: 1.0' ."\r\n";
$headers .= 'Content-Type: text/HTML; charset=ISO-8859-1' . "\r\n";
$headers .= 'Content-Transfer-Encoding: 8bit'. "\n\r\n";
$headers .= $htmlText . "\r\n";
if (!mail('', $strSubject, '', $headers)) { // !!! note the empty parameters.
my new code:
$headers = 'From: ' . $frm . "\r\n";
// note: no "To: " !!!
$headers .= 'Cc: ' . $contactEmailCc . "\r\n";
$headers .= 'Bcc: ' . $contactEmailBcc . "\r\n";
$headers .= 'Return-Path: ' . $frm . "\r\n";
$headers .= 'MIME-Version: 1.0' ."\r\n";
$headers .= 'Content-Type: text/HTML; charset=ISO-8859-1' . "\r\n";
$headers .= 'Content-Transfer-Encoding: 8bit'. "\n\r\n";
// note: no $htmlText !!!
// note: new parameters:
$mTo = $contactEmail;
if ( $flag ) {
$mTo .= ', ' . $contactEmail2;
}
$mMessage .= $htmlText . "\r\n";
if (!mail($mTo, $strSubject, $mMessage, $headers)) {
You may be running into Bug #69874 Can't set empty additional_headers for mail() if you haven't done anything stupid (i.e. forgot to sanitize the headers).
Test for the bug
$ php -d display_errors=1 -d display_startup_errors=1 -d error_reporting=30719 -r 'mail("test#email.com","Subject Here", "Message Here",NULL);'
Warning: mail(): Multiple or malformed newlines found in additional_header in Command line code on line 1
Alternately if you know your PHP version (hint: php -v) you can check the changelog for the bug number (69874) to see whether the fix has been applied for your version.
A short-term fix is to replace calls to mail() like this
function fix_mail( $to , $subject , $message , $additional_headers =NULL, $additional_parameters=NULL ) {
$to=filter_var($to, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES| FILTER_FLAG_STRIP_LOW| FILTER_FLAG_STRIP_HIGH);
$subject=filter_var($subject, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES| FILTER_FLAG_STRIP_LOW| FILTER_FLAG_STRIP_HIGH);
if (!$additional_headers)
return mail( $to , $subject , $message );
if (!$additional_parameters)
return mail( $to , $subject , $message , $additional_headers );
return mail( $to , $subject , $message , $additional_headers, $additional_parameters );
}
Incase this helps anyone, I am using PHP 5.6 and an old code igniter v1 email library
email.php: line 1510 - I've added this:
$this->_header_str = str_replace("\r\r","",$this->_header_str);
$this->_header_str = str_replace("\r\0","",$this->_header_str);
$this->_header_str = str_replace("\r\n\r\n","",$this->_header_str);
$this->_header_str = str_replace("\n\n","",$this->_header_str);
$this->_header_str = str_replace("\n\0","",$this->_header_str);
above this line:
if ( ! mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str, "-f ".$this->clean_email($this->_headers['Return-Path'])))
return FALSE;
else
return TRUE;
And that is successfully sanitising the email headers and resolving the error that I was receiving (same as the original poster of this question)
This is quite possibly someone trying to take advantage of your code to inject email headers.
http://resources.infosecinstitute.com/email-injection/
I would suggest you examine access logs etc and look for unusual activity. The fact you are getting error messages hopefully means that your script has not been compromised and it is erroring out instead. You need to make sure though.
I am sending form data through a .swf file into this PHP page.(see below) When the email is sent, if there is an attachment the body of the message will not appear but if there is not an attachment the body appears just fine. I know that all of the variable names are correct because all of the data has been passed from the swf file. Is there something in the way I have set up the email that makes it work that way? Please let me know.
<?php
$to=$_POST['toEmail'];
$subject=$_POST['subject'];
$body = $_POST['messaggio'];
$nome = $_POST['nome'];
$email = $_POST['email'];
$attach = $_POST['attach'];
$headers = "From: $nome<" . $email . ">\n";
if ($attach == 1) {
$tmp_name = $_FILES['Filedata']['tmp_name'];
$type = $_FILES['Filedata']['type'];
$name = $_FILES['Filedata']['name'];
if(is_uploaded_file($tmp_name)){
$file = fopen($tmp_name,'rb');
$data = fread($file,filesize($tmp_name));
fclose($file);
$data = chunk_split(base64_encode($data));
$headers .= "Reply-To: <" . $email . ">\n";
$headers .= "MIME-Version: 1.0\n";
$headers .= "Content-Type: multipart/related; type=\"multipart/alternative\"; boundary=\"----=MIME_BOUNDARY_main_message\"\n";
$headers .= "X-Sender: $to <" . $to . ">\n";
$headers .= "Return-Path: <" . $email . ">\n";
$headers .= "This is a multi-part message in MIME format.\n";
$headers .= "------=MIME_BOUNDARY_main_message \n";
$headers .= "Content-Type: multipart/alternative; boundary=\"----=MIME_BOUNDARY_message_parts\"\n";
$message = "------=MIME_BOUNDARY_message_parts\n";
$message .= "Content-Type: text/plain; charset=\"iso-8859-1\"\n";
$message .= "Content-Transfer-Encoding: quoted-printable\n";
$message .= "\n";
$message .= $body . "\n";
$message .= "\n";
$message .= "------=MIME_BOUNDARY_message_parts--\n";
$message .= "\n";
$message .= "------=MIME_BOUNDARY_main_message\n";
$message .= "Content-Type: application/octet-stream;\n\tname=\"" . $name . "\"\n";
$message .= "Content-Transfer-Encoding: base64\n";
$message .= "Content-Disposition: attachment;\n\tfilename=\"" . $name . "\"\n\n";
$message .= $data;
$message .= "\n";
$message .= "------=MIME_BOUNDARY_main_message--\n";
mail($to, $subject, $message, $headers);
}
} else {
if(mail($to, $subject, $body, $headers)) {
echo "ok=1";
}
}
?>
Building MIME messages, especially with attachments, is painful. You'd be better off using something like PHPMailer, which will handle the whole business for you automatically... You just have to provide the content.
Beyond that, you're slurping the attachments into memory. How big are they? Are you exceeding the script's memory_limit?