Trouble with Email Attachment in mail() - php

I'm trying to email an image on my server as an attachment. To accomplish this task, I used the following PHP script which grabs a JPG (called "php.jpg") located in a directory called "screenshots" from my server and sends it as an attachment.
<?php
$path = "screenshots/php.jpg";
$fp = fopen($path, 'r');
do //we loop until there is no data left
{
$data = fread($fp, 8192);
if (strlen($data) == 0) break;
$content .= $data;
} while (true);
$content_encode = chunk_split(base64_encode($content));
$mime_boundary = "<<<--==+X[".md5(time())."]";
$headers .= "From: Automatic <an.e.mail#domain.net>\r\n";
$headers .= "To: SomeName <me#gmail.com>\r\n";
$headers .= "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: multipart/mixed;\r\n";
$headers .= " boundary=\"".$mime_boundary."\"";
$message .= "This is a multi-part message in MIME format.\r\n";
$message .= "\r\n";
$message .= "--".$mime_boundary."\r\n";
$message .= "Content-Type: text/plain; charset=\"iso-8859-1\"\r\n";
$message .= "Content-Transfer-Encoding: 7bit\r\n";
$message .= "\r\n";
$message .= "Email content and what not: \r\n";
$message .= "This is the file you asked for! \r\n";
$message .= "--".$mime_boundary."\r\n";
$message .= "Content-Type: image/jpeg;\r\n";
$message .= " name=\"php.jpg\"\r\n";
$message .= "Content-Transfer-Encoding: quoted-printable\r\n";
$message .= "Content-Disposition: attachment;\r\n";
$message .= " filename=\"php.jpg\"\r\n";
$message .= "\r\n";
$message .= $content_encode;
$message .= "\r\n";
$message .= "--".$mime_boundary."\r\n";
$ok = mail("me#gmail.com", "file by email", $message, $headers);
Overall, the script works. I receive an email in my inbox containing the message text specified above and a JPG attachment. Stack Overflow won't let me post a photo because I'm new, but a screenshot of the message is available here: http://i48.tinypic.com/xfuee0.png
My problem occurs when I try to view the attachment. Clicking the attachment simply opens a new browser window and displays a missing image icon.
Do you see any problems with my script that would prevent the image from appearing?
Any info would be great. Thanks!

To anyone who comes across this post in the future, the problem came from the "Content-Transfer-Encoding" which should have been set to base64.
$message .= "Content-Transfer-Encoding: quoted-printable\r\n";
becomes:
$message .= "Content-Transfer-Encoding: base64\r\n";

I can see one possible reason why you're not seeing your image. (There may be more (!).)
Try changing:
$message .= "--".$mime_boundary."\r\n";
to
$message .= "--".$mime_boundary."--\r\n";
For the last line before the call to mail (ie the "epilogue" boundary).

Three things jump out:
One is that the first append to variables $content and $message and $headers doesn't explicitly set a new value. That is, why not
$headers = "From: Automatic <an.e.mail#domain.net>\r\n";
instead of like you have:
$headers .= "From: Automatic <an.e.mail#domain.net>\r\n";
That eliminates the possibility that some leftover stuff is hanging out in the variables.
The second is that there is \r\n instead of plain \n which should work on every system, even Windows. I doubt this is a problem though.
Third is the closing mime boundary isn't the same as the open.

Related

PHP Mail Image attachment not being sent

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.

Window.Open in chrome opens both popus and new tab

I have a strange problem in chrome, I am using window.open to open a new tab and create a pdf using tcpdf and then send it as attachment to a specific address, now in chrome what happens is that it sends 2 mails. If popup is enabled then I get 2 window actions 1. Popup and 2. New Tab, firstly I don't understand how is that possible, I have never seen this.
Then If is disable the popup, it only opens in new tab, but still 2 mails.
Code used to call the popup page and email code is mentioned below. Please help.
window.open('/loancal/rhexportemail.php' + qstring,"_blank");
//Code used to open popup
//------------- EMAIL CODE ----------------//
$to = "someone#gamil.com";
$from = "info#mydomain.com";
$subject = "Loan Enquiry Calculation Cashback - " . $client;
$message = "Please find attached Loan Enquiry Calculation Cashback statement for ".$client."." ;
//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;
// attachment name
$filename = $subject.".pdf";
// encode data (puts attachment in proper format)
$pdfdoc = $pdf->Output('LECC'.$separator.'.pdf', 'S');
$attachment = chunk_split(base64_encode($pdfdoc));
// encode data (multipart mandatory)
$headers = "From: ".$from.$eol;
$headers .= "MIME-Version: 1.0".$eol;
$headers .= "Content-Type: multipart/mixed; boundary=\"".$separator."\"".$eol.$eol;
$headers .= "Content-Transfer-Enconding: 7bit".$eol;
$headers .= "This is a MIME encoded message.".$eol.$eol;
// message
$headers .= "--".$separator.$eol;
$headers .= "Content-Type: text/html; charsrt=\"iso-8859-1\"".$eol;
$headers .= $message.$eol.$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.$eol;
$headers .= $attachment.$eol.$eol;
$headers .= "--".$separator."--";
// send message
if(#mail($to, $subject, $message, $headers))
{
echo "<script type='text/javascript'> alert('mail sent');window.close();</script>";
}
else{
echo "<script type='text/javascript'>alert('mail not sent');window.close(); </script>";
}
I strongly believe that you somehow call this twice.

PHP Sendmail sender name is always Apache when header have attachment

We are trying to send an email using sendmail. Everything works fine with normall headers but the moment we add attachment in the header, the sender name comes as Apache. Here is our code snippet
$from_email = "noreply#domain.com";
$separator = md5(time());
$eol = PHP_EOL;
$filename = "attachment.pdf";
$attachment = chunk_split(base64_encode(file_get_contents($filename)));
$text = "Hi!";
// main header (multipart mandatory)
$headers = "From:".$from_email.$eol;
$headers = "Bcc:user#domain.com".$eol;
$headers .= "MIME-Version: 1.0".$eol;
$headers .= "Content-Type: multipart/mixed; boundary=\"".$separator."\"".$eol.$eol;
$headers .= "Content-Transfer-Encoding: 7bit".$eol;
$headers .= "This is a MIME encoded message.".$eol.$eol;
// message
$message .= "--".$separator.$eol;
$message .= "Content-Type: text/html; charset=\"iso-8859-1\"".$eol;
$message .= "Content-Transfer-Encoding: 8bit".$eol.$eol;
$message .= $text.$eol.$eol;
// attachment
$message .= "--".$separator.$eol;
$message .= "Content-Type: application/pdf".$eol;
$message .= "Content-Transfer-Encoding: base64".$eol;
$message .= "Content-Disposition: attachment; filename=\"".$filename."\"".$eol;
$message .= $attachment.$eol;
$message .= "--".$separator."--".$eol;
$b = mail($email, "Your Issue of the STQ",$message, $headers, "-fnoreply#domain.com");
By Adding -fnoreply#domain.com, we are getting like this in email header From: noreply#domain.com (Apache). Not sure where this Apache is coming from?
What could be the problem here.
Thanks
You need a dot on the second line.
$headers = "From:".$from_email.$eol;
$headers .= "Bcc:user#domain.com".$eol;
Make the header like this :
$headers .= 'From: <webmaster#example.com>' . "\r\n";
Also missing the dot on the second line as xyzz pointed

Attach file to mail using php

I've created a form which contains an upload field file and some other text fields. I'm using php to send the form's data via email and attach the file.
This is the code I'm using but it's not working properly. The file is normally attached to the message but the rest of the data is not sent.
$body="bla bla bla";
$attachment = $_FILES['cv']['tmp_name'];
$attachment_name = $_FILES['cv']['name'];
if (is_uploaded_file($attachment)) {
$fp = fopen($attachment, "rb");
$data = fread($fp, filesize($attachment));
$data = chunk_split(base64_encode($data));
fclose($fp);
}
$headers = "From: $email<$email>\n";
$headers .= "Reply-To: <$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: $first_name $family_name<$email>\n";
$headers .= "X-Mailer: PHP4\n";
$headers .= "X-Priority: 3\n";
$headers .= "Return-Path: <$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/html; charset=\"utf-8\"\n";
$message .= "Content-Transfer-Encoding: quoted-printable\n";
$message .= "\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";
$subject = 'bla bla bla';
$to="test#test.com";
mail($to,$subject,$message,$headers);
Why isn't the $body data not sent? Can you help me fix it?
Well, I'd suggest using the PEAR Mail_Mime package... It abstracts all that away...
As for your exact issue, I'd guess it's because you have two different boundaries and two Content-Type headers in the header section. Try generating something like this:
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="------=MIME_BOUNDARY_MESSAGE_PARTS"
------=MIME_BOUNDARY_MESSAGE_PARTS
Content-Type: text/html charset="utf-8"
$body
------=MIME_BOUNDARY_MESSAGE_PARTS
Content-Type: application/octet-stream;name="filename"
Content-Transfer-Encoding: base64
...
$data
------=MIME_BOUNDARY_MESSAGE_PARTS

PHP mail with attachment - extra file: part 1.4

I'm using the following code to send an email with attachments:
$mime_boundary = "<<<--==+X[".md5(time())."]";
$headers .= "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: multipart/mixed;\r\n";
$headers .= " boundary=\"".$mime_boundary."\"";
$message .= "This is a multi-part message in MIME format.\r\n\r\n";
$message .= "--".$mime_boundary."\r\n";
$message .= "Content-Type: text/plain; charset=\"iso-8859-1\"\r\n";
$message .= "Content-Transfer-Encoding: 7bit\r\n";
$message .= "\r\n";
$message .= "$message_body\r\n";
$message .= "--".$mime_boundary."\r\n";
foreach($attachments as $filename => $data)
{
$message .= "Content-Type: application/octet-stream;\r\n";
$message .= " name=\"$filename\"\r\n";
$message .= "Content-Transfer-Encoding: quoted-printable\r\n";
$message .= "Content-Disposition: attachment;\r\n";
$message .= " filename=\"$filename\"\r\n";
$message .= "\r\n";
$message .= chunk_split(base64_encode($data));
$message .= "\r\n";
$message .= "--".$mime_boundary."\r\n";
}
mail($email_address, $email_subject, $message, $headers);
Which works fine, except that an extra file is also attached (called "Part 1.4").
Is there a way to not have this added?
Cheers,
Dan.
IIRC the last part separator must be --something unique--, i.e. in your case
$message .= "--".$mime_boundary."--\r\n";
But mime mail is more or less a solved problem ( i.e. for an application developer it's boring when done correctly and reeeeally annoying when done wrong ;-) ). Do yourself a favor and use something like Swiftmailer or any other descend mailing library/class.

Categories