For some reason in php when sending a "multipart/alternative" email it seems to double-up new lines messing up the formatting for plain-text clients.
Here's my code:
$boundary = uniqid('np');
// To send HTML mail, the Content-type header must be set
$headers = 'MIME-Version: 1.0' . "\r\n";
$headers .= "Content-Type: multipart/alternative;charset=utf-8;boundary=" . $boundary . "\r\n";
$headers .= "From: GamingOnLinux.com Notification <noreply#gamingonlinux.com>\r\n" . "Reply-To: noreply#gamingonlinux.com\r\n";
$message .= "\r\n\r\n--" . $boundary . "\r\n";
$message .= "Content-Type: text/plain;charset=utf-8\r\n";
$message .= "Content-Transfer-Encoding: 7bit\r\n";
$message .= $plain_message;
$message .= "\r\n\r\n--" . $boundary . "\r\n";
$message .= "Content-Type: text/html;charset=utf-8\r\n";
$message .= "Content-Transfer-Encoding: 7bit\r\n";
$message .= "$html_message";
$message .= "\r\n\r\n--" . $boundary . "--";
// Mail it
mail($to, $subject, $message, $headers);
So it ends up coming out like this:
--np53494d20d247e
Content-Type: text/plain;charset=utf-8
Content-Transfer-Encoding: 7bit
When there should be no line between them?
You are currently using MS-Windows style line endings (\r\n). Use Unix style line endings instead (\n) and most likely your issue is solved.
Different systems traditionally encode line ending different. But the unixoid version is the one which probably can be considered the "internet native style", since the internet (thus all network exchange stuff) was developed based on unixoid systems. Actually things were more complex, this obviously is a simplification. Therefore most (at least all sane) clients like email programs should be able to handle and disply such line ending correctly, whilst the MS-Windows style looks "funny" to many of them.
Related
I created a codes using php its working already with attachment but its only .doc i want to change it to .pdf i tried to change the application/msword to application/pdf and the file name from PO.doc to PO.pdf but its corrupted when i receive it on my email. Can you suggest me what should i do? Below is my codes for that. Thank you.
<?php
$headers = "From:<noreply#example.com>";
$to = 'email#example.com';
$subject = 'Purchase Order';
$txt .="
<html>
<body>
<p><b> PO Number:</b> $purchasenumber</p>
<p><b> Style Code:</b> $styleCode</p>
<p><b> Generic Number:</b> $gennum</p>
<p><b> Vendor Name:</b> $vendname</p>
<p><b> Planned Delivery Date:</b> $pdelivdate</p> <br/> <br/>";
// Always set content-type when sending HTML email
$message = "MIME-Version: 1.0" . "\r\n";
// $headers .= "Content-type:text/html;charset=UTF-8" . "\r\n";
$message .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n";
$fileatt_name2 = "PurchaseOrder.doc";
$semi_rand = md5(time());
$mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";
// Add the headers for a file attachment
$headers .= "\nMIME-Version: 1.0\n" .
"Content-Type: multipart/mixed;\n" .
" boundary=\"{$mime_boundary}\"";
$data2 = chunk_split(base64_encode($txt));
$message = "{$mime_boundary}\n" .
"Content-Type: text/plain; charset=iso-8859-1; format=flowed\n" .
"Content-Transfer-Encoding: 7bit\n\n" .
$message .= "{$mime_boundary}\n" .
"Content-Type: text/plain; charset=\"iso-8859-1\"\n" .
"Content-Transfer-Encoding: 7bit\n\n" .
// Add file attachment to the message
$message .= "--{$mime_boundary}\n" .
"Content-Type: application/msword;\n" . // {$fileatt_type}
" name=\"{$fileatt_name2}\"\n" .
"Content-Disposition: attachment;\n" .
" filename=\"{$fileatt_name2}\"\n" .
"Content-Transfer-Encoding: base64\n\n" .
$data2 . "\n\n" .
"--{$mime_boundary}--\n";
// Send the message
$send = mail($to, $subject, $message, $headers);
?>
This is not as simple as changing the extension (.doc, .pdf etc.) to convert a file from one type to the other. A more specialized process is needed. What you tried is analogous to taking an apple and dressing it up as a pear. It may look like a pear at first, but when taking a bite you'd discover it is actually an apple.
If you want to convert the .doc to a PDF you can convert it using programs like Microsoft Word (although I'm sure that Libre- or Open-office can do this too). If a more automated manner is desired, consider implementing other solutions like livedocs or phpdocs although the latter is quite pricy.
Depending on the platform (Linux, Windows, OSX) other options might be available as was answered in questions like this one.
Just to be clear - I didn't write this code, this is from a previous developer.
Anyway, my client isn't receiving images when uploaded via their form, just a red box with an error message.
As per request here is the whole code:
<?php
function sendMail() {
if (!isset ($_POST['to_email'])) { //Oops, forgot your email addy!
die ("<p>Oops! You forgot to fill out the email address! Click on the back arrow to go back</p>");
}
else {
$to_name = stripslashes($_POST['to_name']);
$from_name = stripslashes($_POST['from_name']);
$from_telephone = stripslashes($_POST['from_telephone']);
$subject = stripslashes($_POST['subject']);
$body = stripslashes($_POST['body']);
$address = stripslashes($_POST['address']);
$to_email = $_POST['to_email'];
$attachment = $_FILES['attachment']['tmp_name'];
$attachment_name = $_FILES['attachment']['name'];
if (is_uploaded_file($attachment)) { //Do we have a file uploaded?
$fp = fopen($attachment, "rb"); //Open it
$data = fread($fp, filesize($attachment)); //Read it
$data = chunk_split(base64_encode($data)); //Chunk it up and encode it as base64 so it can emailed
fclose($fp);
}
//Let's start our headers
$headers = "From: $from_name<" . $_POST['from_email'] . ">\n";
$headers .= "Reply-To: <" . $_POST['from_email'] . ">\n";
$headers .= "MIME-Version: 1.0\n";
$headers .= "Content-Type: multipart/related; type=\"multipart/alternative\"; boundary=\"----=MIME_BOUNDRY_main_message\"\n";
$headers .= "X-Sender: $from_name<" . $_POST['from_email'] . ">\n";
$headers .= "X-Mailer: PHP4\n";
$headers .= "X-Priority: 3\n"; //1 = Urgent, 3 = Normal
$headers .= "Return-Path: <" . $_POST['from_email'] . ">\n";
$headers .= "This is a multi-part message in MIME format.\n";
$headers .= "------=MIME_BOUNDRY_main_message \n";
$headers .= "Content-Type: multipart/alternative; boundary=\"----=MIME_BOUNDRY_message_parts\"\n";
$message = "------=MIME_BOUNDRY_message_parts\n";
$message .= "Content-Type: text/plain; charset=\"iso-8859-1\"\n";
$message .= "Content-Transfer-Encoding: quoted-printable\n";
$message .= "\n";
/* Add our message, in this case it's plain text. You could also add HTML by changing the Content-Type to text/html */
$message .= "Return call on: $from_telephone\n\n";
$message .= "$address\n\n";
$message .= "$body\n";
$message .= "\n";
$message .= "------=MIME_BOUNDRY_message_parts--\n";
$message .= "\n";
$message .= "------=MIME_BOUNDRY_main_message\n";
$message .= "Content-Type: application/octet-stream;\n\tname=\"" . $attachment_name . "\"\n";
$message .= "Content-Transfer-Encoding: base64\n";
$message .= "Content-Disposition: attachment;\n\tfilename=\"" . $attachment_name . "\"\n\n";
$message .= $data; //The base64 encoded message
$message .= "\n";
$message .= "------=MIME_BOUNDRY_main_message--\n";
// send the message
mail("$to_name<$to_email>", $subject, $message, $headers);
print "<p align=\"center\">Thank you for your email.</p>";
}
}
switch ($action) {
case "send":
showForm();
sendMail();
break;
default:
showForm();
}
?>
I'm completely confused by this code as I didn't write it and can't decrypt why "$attachment" and "$attachment_name" are separate strings, if I change the "attachment_name" to "attachment" will my problems be fixed?
The code that you have seems to work for me, but there are a few potential problems. I think perhaps the most important one is that the image is sent using an incorrect Content-Type:, but there are also some other issues detailed below.
Image type
$message .= "Content-Type: application/octet-stream;\n\tname=\"" . $attachment_name . "\"\n";
The application/octet-stream is used as a last resort for sending arbitrary binary data when there is no appropriate content type, or the content type is unknown. You should use a proper image type:
$message .= "Content-Type: " . $_FILES['attachement']['type']
. ";\n\tname=\"" . $attachment_name . "\"\n";
If you want to prevent users from mailing arbitrary files, you can use a white-list:
if (is_uploaded_file($attachment) &&
in_array ($attachment_type, array ('image/gif', 'image/png', 'image/jpg', 'image/jpeg'))) {
$fp = fopen($attachment, "rb"); //Open it
$data = fread($fp, filesize($attachment)); //Read it
$data = chunk_split(base64_encode($data)); //Chunk it up and encode it as base64 so it can emailed
fclose ($fp);
} else {
echo "<p>Useful error message\n";
exit;
}
MIME syntax
$headers .= "X-Priority: 3\n"; //1 = Urgent, 3 = Normal
$headers .= "Return-Path: <" . $_POST['from_email'] . ">\n";
$headers .= "This is a multi-part message in MIME format.\n";
The Return-Path: is the last of your headers. The next line is part of the message body. You need a blank line to separate the message body from the headers. Eg:
$headers .= "Return-Path: <" . $_POST['from_email'] . ">\n";
$headers .= "\n";
$headers .= "This is a multi-part message in MIME format.\n";
Personally, I would add the message body to $message instead. The mail() function doesn't care, it just concatenates the headers and message with a line break. See more about line endings below.
$headers .= "------=MIME_BOUNDRY_main_message \n";
$headers .= "Content-Type: multipart/alternative; boundary=\"----=MIME_BOUNDRY_message_parts\"\n";
$message = "------=MIME_BOUNDRY_message_parts\n";
Note that if you do move some of the lines above to $message, you need to insert an extra line break after the Content-Type: header.
$attachment = $_FILES['attachment']['tmp_name'];
$attachment_name = $_FILES['attachment']['name'];
...
$message .= "Content-Disposition: attachment;\n\tfilename=\"" . $attachment_name . "\"\n\n";
$attachment_name is sent by the browser and is typically the original name of the file uploaded by the user. $attachment is the name of the temporary file where the image is stored on the server. The two are entirely different and are not interchangeable.
You may want to strip control characters (such as line breaks) and double quotes from these variables to prevent malicious users from disrupting the syntax of the headers.
Line endings
According to the Mail syntax, lines should be terminated with a CRLF("\r\n") sequence, but it is not clear which line ending should be used when calling the mail() function. The PHP documentation says:
If messages are not received, try using a LF (\n) only. Some Unix mail transfer agents (most notably » qmail) replace LF by CRLF automatically (which leads to doubling CR if CRLF is used). This should be a last resort, as it does not comply with » RFC 2822.
$_POST[] data
You should not use raw data from $_POST[] in your mail headers. A malicious user could easily insert their own headers (such as Bcc:) to send spam to arbitrary addresses. You should at least filter out control characters (such as line breaks) and perhaps also filter or escape angle brackets and double quotes depending on usage.
I am trying to send a multipart mail that contains both html and plain text. This is also one of the ways to get through spam filters and to allow more people to read the mail in case of not supporting HTML. After spending long hours googling, I have found some examples. I made my code, which sends the mail but it displays the text with the html tags, code, string etc.
<?php
$boundary=md5(uniqid(rand()));
$header .= "From:My Name<something#something.com>\n";
$header .= "Reply-To: something#something.com \n";
$header .= 'MIME-Version: 1.0'."\r\n";
$header .= 'Content-type: multipart/alternative;boundary=$boundary '."\n";
$adres = "something#gmail.com";
$subject = "subject";
$message = "This is multipart message using MIME\n";
$message .= "--" . $boundary . "\n";
$message .= "Content-type: text/plain;charset=iso-8859-1\n";
$message .= "Content-Transfer-Encoding: 7bit". "\n\n";
$message .= "Plain text version\n\n";
$message .="--" . $boundary . "\n";
$message .="Content-type: text/html;charset=iso-8859-1\n";
$message .= "Content-Transfer-Encoding: 7bit". "\n\n";
$message .="<html>
<body>
<center>
<b>HTML text version</b>
</center>
</body>
</html>\n\n";
$message .= "--" . $boundary . "--";
if(mail($adres, $subject, $message, $header))
{
print'message sent';
}
else
{
print'message was not sent';
}
?>
This is the result:
This is multipart message using MIME
--c071adfa945491cac7759a760ff8baeb
Content-type: text/plain;charset=iso-8859-1
Content-Transfer-Encoding: 7bit
Plain text version
--c071adfa945491cac7759a760ff8baeb
Content-type: text/html;charset=iso-8859-1
Content-Transfer-Encoding: 7bit
<html>
<body>
<center>
<b>HTML text version</b>
</center>
</body>
</html>
--c071adfa945491cac7759a760ff8baeb--
As you can see it displays the coding instead of the message alone. I have tried many solutions posted like:
adding/removing \r\n;
changing \r\n to \n;
changing content type from alternative to mixed;
I am learning PHP and all I know is all I have read and done so far. I have still much to learn so please if you could tell me where is the problem. I would be very thankful.Best regards.
The line:
$header .= 'Content-type: multipart/alternative;boundary=$boundary '."\n";
Has the wrong quotes, so $boundary won't be expanded. Change to:
$header .= "Content-type: multipart/alternative;boundary=$boundary\n";
And like I said in the comments, in the message headers and the content section headers you should be using \r\n as the line break since that's what is defined in the RFC. Most MTAs will allow simply \n, but some will choke on the message, and some spam filters will count every RFC violation as a point towards your spam score.
Using something like PHPMailer is a much better option because it formats everything perfectly by default, and abides by just about every single obscure, boring RFC.
I think you need quotes around the boundary string.
try this:
$header .= 'Content-type: multipart/alternative; boundary="' . $boundary . '"\r\n';
Try this example https://github.com/breakermind/PhpMimeParser/blob/master/PhpMimeClient_class.php
$m = new PhpMimeClient();
// Add to
$m->addTo("email#star.ccc", "Albercik");
$m->addTo("adela#music.com", "Adela");
// Add Cc
$m->addCc("zonk#email.au");
// Add Bcc
$m->addBcc("boos#domain.com", "BOSS");
// Add files inline
$m->addFile('photo.jpg',"zenek123");
// Add file
$m->addFile('sun.png');
// create mime
$m->createMime("Witaj!",'<h1>Witaj jak się masz? <img src="cid:zenek123"> </h1>',"Wesołych świąt życzę!","Heniek Wielki", "hohoho#domain.com");
// get mime
// $m->getMime();
// Show mime
echo nl2br(htmlentities($m->getMime()));
Here is the complete script without errors:
<?php
error_reporting(-1);
ini_set("display_errors", "1");
$mailto = "email#enter-domainname-here.com";
$subject = "subject";
$boundary=md5(uniqid(rand()));
$header = "From:Info<".$mailto.">\n";
$header .= "Reply-To: ".$mailto."\n";
$header .= "MIME-Version: 1.0"."\n";
$header .= "Content-type: multipart/alternative; boundary=\"----=_NextPart_" . $boundary . "\"";
$message = "This is multipart message using MIME\n";
$message .= "------=_NextPart_" . $boundary . "\n";
$message .= "Content-Type: text/plain; charset=UTF-8\n";
$message .= "Content-Transfer-Encoding: 7bit". "\n\n";
$message .= "Plain text version\n\n";
$message .="------=_NextPart_" . $boundary . "\n";
$message .="Content-Type: text/html; charset=UTF-8\n";
$message .= "Content-Transfer-Encoding: 7bit". "\n\n";
$message .="<html>
<body>
<center>
<b>HTML text version</b>
</center>
</body>
</html>\n\n";
$message .= "------=_NextPart_" . $boundary . "--";
if(#mail($mailto, $subject, $message, $header))
{
print'message sent';
}
else
{
print"message was not sent";
}
?>
I am testing an auto reply multipart email using PHP. The problem is when I receive the email in my hotmil, the whole content (including html and the random hashes) appears as raw text. Here is my code:
$cname = "test";
$to = "me#myemail.com";
$autoReplyTo = "me#myemail.com";
$autoReplySubject = "Enquiry";
$mime_boundary = md5(date('U'));
$autoReplyheaders = "From: XXXXX <" . $to . ">" . "\r\n" .
"MIME-Version: 1.0" . "\r\n" .
"Content-Type: multipart/alternative; boundary=$mime_boundary" .
"Content-Transfer-Encoding: 7bit". "\r\n";
$plain_text = "Dear " . $cname . ".\r\n";
$plain_text = "Thank you for contacting us.\r\n";
$plain_text .= "We are currently processing your query and will contact you shortly. We appreciate the time and interest you have shown in our company.\r\n";
$plain_text .= "Sales Team\r\n";
$plain_text .= "Note: This is an auto-generated email, please do not reply.\r\n";
$html_text = '<html><head><title>AUTO REPLY</title></head><body>';
$html_text .= '<p><img src="http://www.xxxxxx.xx/images/logo.png" /></p>';
$html_text .= '<p>Dear '.$cname.',<br />
Thank you for contacting us.<br />
We are currently processing your query and will contact you shortly.<br />
We appreciate the time and interest you have shown in our company.</p>';
$html_text .= '<p><b>Sales Team</b></p>';
$html_text .= '<p><i>Note: This is an auto-generated email, please do not reply.</i></p>';
$html_text .= '</body></html>';
$autoReplyMessage = "Auto reply" . "\r\n\r\n".
"--" . $mime_boundary.
"Content-Type: text/plain; charset=\"iso-8859-1\"".
"Content-Transfer-Encoding: 7bit". "\r\n\r\n".
$plain_text.
"--" . $mime_boundary.
"Content-Type: text/html; charset=\"iso-8859-1\"".
"Content-Transfer-Encoding: 7bit". "\r\n\r\n".
$html_text.
"--".$mime_boundary."--";
mail($autoReplyTo, $autoReplySubject, $autoReplyMessage, $autoReplyheaders);
What am I doing wrong?
This may or may not be the only issue, but you are missing line breaks after the Content-Type headers in the plain and HTML sections:
$autoReplyMessage = "Auto reply" . "\r\n\r\n".
"--" . $mime_boundary.
"Content-Type: text/plain; charset=\"iso-8859-1\"\r\n".
// ----------------------------------------------^^^^^
// Added \r\n
"Content-Transfer-Encoding: 7bit". "\r\n\r\n".
$plain_text. "\r\n".
//---------^^^^^^^^^
// Added another linebreak before MIME boundary
"--" . $mime_boundary.
"Content-Type: text/html; charset=\"iso-8859-1\"\r\n".
// ----------------------------------------------^^^^^
// Added \r\n
"Content-Transfer-Encoding: 7bit". "\r\n\r\n".
$html_text."\r\n\r\n".
// ---------^^^^^^^^^^
"--".$mime_boundary."--";
Rather than attempt to craft multipart/mime messages manually, lots of us here on SO would recommend a mailing library like PHPMailer which handles this much more easily. Building messages manually tends to be quite error-prone, and subject to inconsistencies between implementations by the SMTP server, or differences between native platform linebreaks.
I'm having a challenge with sending emails with arabic content using PHP's mail function. Let's say I have this simple arabic string:
بريد
I've tried several ways to utilize the headers, but the emails content all still end up with something like: X*X1X(X1Y X/. However, the email subject is correctly encoded if I use arabic characters (thanks to the base64_encode, see function below)
Here's one of the email functions I've tried
function sendSimpleMail($to,$from,$subject,$message) {
$headers = 'MIME-Version: 1.0' ."\r\n";
$headers .= 'To: '.$to ."\r\n";
$headers .= 'From: '.$from . "\r\n";
$headers .= 'Content-type: text/plain; charset=UTF-8; format=flowed' . "\r\n";
$headers .= 'Content-Transfer-Encoding: 8bit'."\r\n";
mail($to, '=?UTF-8?B?'.base64_encode($subject).'?=',$message, $headers);
}
Any suggestions on alternative ways to achieve this goal?
Unfortunately, 8bit encoding is not reliable in e-mail. Many mail transport agents will remove the top bit of every byte in the mail body. بريد is "\xD8\xA8\xD8\xB1\xD9\x8A\xD8\xAF" in UTF-8 bytes; remove the top bit from those bytes and you get ASCII "X(X1Y\nX/".
The way to get non-ASCII characters into a mail body is to set Content-Transfer-Encoding to either base64 or quoted-printable, and the encode the body with base64_encode or quoted_printable_encode, respectively.
(quoted-printable is better if the mail is largely ASCII as it retains readability in the encoded form and is more efficient for ASCII. If the whole mail is Arabic, base64 would probably be the better choice.)
$boundary = uniqid(rand(), true);
$headers = "From: $from\n";
$headers .= "MIME-Version: 1.0\n";
$headers .= "Content-Type: multipart/alternative; boundary = $boundary\n";
$headers .= "This is a MIME encoded message.\n\n";
$headers .= "--$boundary\n" .
"Content-Type: text/plain; charset=UTF-8 \n" .
"Content-Transfer-Encoding: base64\n\n";
$headers .= chunk_split(base64_encode($plaintext));
$headers .= "--$boundary\n" .
"Content-Type: text/html; charset=ISO-8859-1\n" .
"Content-Transfer-Encoding: base64\n\n";
$headers .= chunk_split(base64_encode($msg));
$headers .= "--$boundary--\n" .
mail($address, $subject, '', $headers);
This one works for me.
Try this
$headers .= 'From: =?UTF-8?B?'.base64_encode($from). "\r\n";
Your code works for me as-is.
Are you sure that $message contains a valid UTF-8 string?