Nodral Posted March 19, 2012 Share Posted March 19, 2012 Hi All I'm trying to send an email with an attachment, but all I get is the content and the MIME headers coming through as plain text in the body. It needs to be HTML with a pdf attachment. Any thoughts what I'm doing wrong. My knowledge of MIME headers etc is as limited as cutting and pasting this code from Google, and amending it to try to do what I need. function emailJI($to, $subject, $attachment, $content){ /* Email Detials */ $mail_to = "$to"; $from_mail = "Admin@*****.co.uk"; $from_name = "***** Administrator"; $reply_to = "*****.*****@*****.com"; $subject = "$subject"; $message = "$content"; /* Attachment File */ // Attachment location $file_name = "prebrief.pdf"; $path = "prebrief.pdf"; // Read the file content $file = $path.$file_name; $file_size = filesize($file); $handle = fopen($file, "r"); $content = fread($handle, $file_size); fclose($handle); $content = chunk_split(base64_encode($content)); /* Set the email header */ // Generate a boundary $boundary = md5(uniqid(time())); // Email header $header = "From: ".$from_name." <".$from_mail.">\r\n"; $header .= "Reply-To: ".$reply_to."\r\n"; $header .= "MIME-Version: 1.0\r\n"; // Multipart wraps the Email Content and Attachment $header .= "Content-Type: multipart/mixed; boundary=\"".$boundary."\"\r\n"; $header .= "This is a multi-part message in MIME format.\r\n"; $header .= "--".$boundary."\r\n"; // Email content // Content-type can be text/plain or text/html //$header .= "Content-type:text/plain; charset=iso-8859-1\r\n"; $header .= "Content-Transfer-Encoding: 7bit\r\n\r\n"; $header .= "$message\r\n"; $header .= "--".$boundary."\r\n"; // Attachment // Edit content type for different file extensions $header .= "Content-Type: application/pdf; name=\"".$file_name."\"\r\n"; $header .= "Content-Transfer-Encoding: base64\r\n"; $header .= "Content-Disposition: attachment; filename=\"".$file_name."\"\r\n\r\n"; $header .= $content."\r\n"; $header .= "--".$boundary."--"; // Send email if (mail($mail_to, $subject, "", $header)) { echo "Sent"; } else { echo "Error"; } } Quote Link to comment https://forums.phpfreaks.com/topic/259262-email-with-attachemnt/ Share on other sites More sharing options...
Muddy_Funster Posted March 19, 2012 Share Posted March 19, 2012 change your \r\n to just \n and double check how many \n's to use for each header line. Quote Link to comment https://forums.phpfreaks.com/topic/259262-email-with-attachemnt/#findComment-1329064 Share on other sites More sharing options...
Nodral Posted March 19, 2012 Author Share Posted March 19, 2012 Ok, attachment coming through now, but it is saying it cannot be opened as it wasn't encoded properly, and the message is still plain text and not HTML. Here's my amended code /* Attachment File */ // Attachment location $file_name = "prebrief.pdf"; $path = "prebrief.pdf"; // Read the file content $file = $path.$file_name; $file_size = filesize($file); $handle = fopen($file, "r"); $content = fread($handle, $file_size); fclose($handle); $content = chunk_split(base64_encode($content)); /* Set the email header */ // Generate a boundary $boundary = md5(uniqid(time())); // Email header $header = "From: ".$from_name." <".$from_mail.">\n"; $header .= "Reply-To: ".$reply_to."\n"; $header .= "MIME-Version: 1.0\n"; // Multipart wraps the Email Content and Attachment $header .= "Content-Type: multipart/mixed; boundary=\"".$boundary."\"\n"; $header .= "This is a multi-part message in MIME format.\n"; $header .= "--".$boundary."\r\n"; // Email content // Content-type can be text/plain or text/html //$header .= "Content-type:text/plain; charset=iso-8859-1\r\n"; $header .= "Content-Transfer-Encoding: 7bit\n"; $header .= "$message\n"; $header .= "--".$boundary."\n"; // Attachment // Edit content type for different file extensions $header .= "Content-Type: application/pdf; name=\"".$file_name."\"\n"; $header .= "Content-Transfer-Encoding: base64\n"; $header .= "Content-Disposition: attachment; filename=\"".$file_name."\"\n"; $header .= $content."\n"; $header .= "--".$boundary."--"; // Send email if (mail($mail_to, $subject, "", $header)) { echo "Sent"; } else { echo "Error"; } } Quote Link to comment https://forums.phpfreaks.com/topic/259262-email-with-attachemnt/#findComment-1329067 Share on other sites More sharing options...
Muddy_Funster Posted March 19, 2012 Share Posted March 19, 2012 you still have your Content-type declaration for the mail body commented out (and set to text/plain), try commenting out the base64 encoding line for the attachment, you don't need to encode it to send it, just to see if it will open. Quote Link to comment https://forums.phpfreaks.com/topic/259262-email-with-attachemnt/#findComment-1329072 Share on other sites More sharing options...
DavidAM Posted March 19, 2012 Share Posted March 19, 2012 It's been a while since I did this, but: 1) The specification says the headers are terminated with CRLF not just LF 2) The mime message is the BODY not a header (see my comment line below): // Email header $header = "From: ".$from_name." <".$from_mail.">\n"; $header .= "Reply-To: ".$reply_to."\n"; $header .= "MIME-Version: 1.0\n"; // Multipart wraps the Email Content and Attachment $header .= "Content-Type: multipart/mixed; boundary=\"".$boundary."\"\n"; # I BELIEVE EVERYTHING BELOW HERE SHOULD BE THE BODY NOT PART OF THE HEADERS $header .= "This is a multi-part message in MIME format.\n"; $header .= "--".$boundary."\r\n"; // Email content // Content-type can be text/plain or text/html //$header .= "Content-type:text/plain; charset=iso-8859-1\r\n"; $header .= "Content-Transfer-Encoding: 7bit\n"; $header .= "$message\n"; $header .= "--".$boundary."\n"; // Attachment // Edit content type for different file extensions You are putting everything in the headers and sending an empty body. In a raw email stream, the first blank line separates the headers from the body. So putting everything in the headers might work, if the blank line is put in the right place. However, I don't know what PHP's mail() function does with the headers --- does it remove extra blank lines? --- so I would separate them. Quote Link to comment https://forums.phpfreaks.com/topic/259262-email-with-attachemnt/#findComment-1329074 Share on other sites More sharing options...
Muddy_Funster Posted March 19, 2012 Share Posted March 19, 2012 .... 1) The specification says the headers are terminated with CRLF not just LF .... the specification for what? because the only reliable way I could get a multipart message to send when writing my mail function was to use \n and NOT \r\n Quote Link to comment https://forums.phpfreaks.com/topic/259262-email-with-attachemnt/#findComment-1329078 Share on other sites More sharing options...
Nodral Posted March 19, 2012 Author Share Posted March 19, 2012 OK, the message comes through nicely as HTML now, however the attachment is still saying it's corrupted and not been decoded correctly /* Attachment File */ // Attachment location $file_name = "prebrief.pdf"; $path = "prebrief.pdf"; // Read the file content $file = $path.$file_name; $file_size = filesize($file); $handle = fopen($file, "r"); $att = fread($handle, $file_size); fclose($handle); $att = chunk_split(base64_encode($att)); /* Set the email header */ // Generate a boundary $boundary = md5(uniqid(time())); // Email header $header = "From: ".$from_name." <".$from_mail.">\n"; $header .= "Reply-To: ".$reply_to."\n"; $header .= "MIME-Version: 1.0\n"; // Multipart wraps the Email Content and Attachment $header .= "Content-Type: multipart/mixed; boundary=\"".$boundary."\"\n"; $header .= "This is a multi-part message in MIME format.\n"; $header .= "--".$boundary."\n"; // Email content // Content-type can be text/plain or text/html $header .= "Content-type:text/html; charset=iso-8859-1\n"; $header .= "Content-Transfer-Encoding: 7bit\n"; $header .= "$message\n"; $header .= "--".$boundary."\n"; // Attachment // Edit content type for different file extensions $header .= "Content-Type: application/pdf; name=\"".$file_name."\"\n"; //$header .= "Content-Transfer-Encoding: base64\n"; $header .= "Content-Disposition: attachment; filename=\"".$file_name."\"\n"; $header .= $att."\n"; $header .= "--".$boundary."--"; // Send email if (mail($mail_to, $subject, "", $header)) { echo "Sent"; } else { echo "Error"; } Quote Link to comment https://forums.phpfreaks.com/topic/259262-email-with-attachemnt/#findComment-1329083 Share on other sites More sharing options...
Muddy_Funster Posted March 19, 2012 Share Posted March 19, 2012 it could be a problem with the file loading, try sending some raw html as the attachment (just remember to change the Content-Type for the attachment before you send it. Also, add another \n after the attachment so it looks like this: // Edit content type for different file extensions $header .= "Content-Type: text/html; name=\"test.html\"\n"; $header .= "Content-Transfer-Encoding: base64\n"; $header .= "Content-Disposition: attachment; filename=\"".$file_name."\"\n"; $att= "<html><head><title></title></head><body>Test attachment for mail delivery</body></html>"; $header .= $att."\n\n"; Quote Link to comment https://forums.phpfreaks.com/topic/259262-email-with-attachemnt/#findComment-1329091 Share on other sites More sharing options...
DavidAM Posted March 19, 2012 Share Posted March 19, 2012 .... 1) The specification says the headers are terminated with CRLF not just LF .... the specification for what? because the only reliable way I could get a multipart message to send when writing my mail function was to use \n and NOT \r\n RFC 5322 (and its predecessor, RFC 2822) state: A message consists of header fields (collectively called "the header section of the message") followed, optionally, by a body. The header section is a sequence of lines of characters with special syntax as defined in this specification. The body is simply a sequence of characters that follows the header section and is separated from the header section by an empty line (i.e., a line with nothing preceding the CRLF). and Header fields are lines beginning with a field name, followed by a colon (":"), followed by a field body, and terminated by CRLF. A field name MUST be composed of printable US-ASCII characters (i.e., characters that have values between 33 and 126, inclusive), except colon. A field body may be composed of printable US-ASCII characters as well as the space (SP, ASCII value 32) and horizontal tab (HTAB, ASCII value 9) characters (together known as the white space characters, WSP). A field body MUST NOT include CR and LF except when used in "folding" and "unfolding", as described in section 2.2.3. All field bodies MUST conform to the syntax described in sections 3 and 4 of this specification. Edit As with most internet content, many readers (i.e. browsers and email clients) choose to interpret the standard loosely. So some readers may not care if the headers have the CR part. But, since the headers have to be read by the email transport servers -- that is, all servers handling the mail along the way -- it is a good idea to follow the standard. Some transport servers may not handle the headers properly without the CR in the line terminator; and some readers (clients) may not handle the headers properly without it. Quote Link to comment https://forums.phpfreaks.com/topic/259262-email-with-attachemnt/#findComment-1329096 Share on other sites More sharing options...
Muddy_Funster Posted March 19, 2012 Share Posted March 19, 2012 ahh....yeah, that doesn't reliably work in practice though. I only spent two full days trying before I managed to get a working function using only the \n and not the \r\n, and it may very well be down to something as distant as how windows handles a new line over how linux does, but I'm just sticking with what I know. Quote Link to comment https://forums.phpfreaks.com/topic/259262-email-with-attachemnt/#findComment-1329102 Share on other sites More sharing options...
KevinM1 Posted March 19, 2012 Share Posted March 19, 2012 Why are your $path and $file_name the same? Quote Link to comment https://forums.phpfreaks.com/topic/259262-email-with-attachemnt/#findComment-1329108 Share on other sites More sharing options...
Nodral Posted March 19, 2012 Author Share Posted March 19, 2012 $name is what it will be displayed as on the email $path is the actual location of the file on the server Quote Link to comment https://forums.phpfreaks.com/topic/259262-email-with-attachemnt/#findComment-1329111 Share on other sites More sharing options...
Nodral Posted March 19, 2012 Author Share Posted March 19, 2012 Ok, I've changed the file to HTML as suggested, and I just get a load of Gobble-de-gook symbols. Hmmmmmm, strangerer and strangerer. any more ideas guys? Quote Link to comment https://forums.phpfreaks.com/topic/259262-email-with-attachemnt/#findComment-1329113 Share on other sites More sharing options...
KevinM1 Posted March 19, 2012 Share Posted March 19, 2012 You have: $file_name = "prebrief.pdf"; $path = "prebrief.pdf"; $file = $path.$file_name; Which means $file is equal to prebrief.pdfprebrief.pdf. Could be a problem, no? Quote Link to comment https://forums.phpfreaks.com/topic/259262-email-with-attachemnt/#findComment-1329114 Share on other sites More sharing options...
Nodral Posted March 19, 2012 Author Share Posted March 19, 2012 ok, corrected that, But using the HTML as muddy suggested outputs †Ù¥…æ¶+e{ûb¶W¿…æn‡rMë-jÛZržž×è®f¢•×¥Š÷«Ëöèw/á Quote Link to comment https://forums.phpfreaks.com/topic/259262-email-with-attachemnt/#findComment-1329115 Share on other sites More sharing options...
Muddy_Funster Posted March 19, 2012 Share Posted March 19, 2012 Just checked the layout on my function, I think it's the order you have things in your header, this is the working order I use : $message .= "Content-type:application/octet-stream;"; //set content type to suitable type for attachment (octet-stream is for generic binary data other are available) $message .= "name=\"$fName\"".$e; //set the file name $message .= "Content-disposition:attachment;"; //use attachment to infer data that is being passed as a file $message .= "filename=\"$fName.xml\";".$e; //set the filename as it will be recieved $message .= "Content-transfer-encoding:base64".$e.$e; // encode the file for transfer $message .= $attachment.$e.$e; // add attachment contents $e contains \n for line break. Quote Link to comment https://forums.phpfreaks.com/topic/259262-email-with-attachemnt/#findComment-1329120 Share on other sites More sharing options...
Nodral Posted March 20, 2012 Author Share Posted March 20, 2012 This still not working. If I remove the encoding then the HTML we tested with comes through fine, but if I use pdf then it says encoding is wrong. Please Please Please someone help with this, I can't fathom it at all. Quote Link to comment https://forums.phpfreaks.com/topic/259262-email-with-attachemnt/#findComment-1329452 Share on other sites More sharing options...
Muddy_Funster Posted March 20, 2012 Share Posted March 20, 2012 ok, post me up the full thing as it is just now and I'll run it over on this end, see what I can sus out. Quote Link to comment https://forums.phpfreaks.com/topic/259262-email-with-attachemnt/#findComment-1329458 Share on other sites More sharing options...
Nodral Posted March 20, 2012 Author Share Posted March 20, 2012 function emailJI($to, $subject, $attachment, $content){ /* Email Detials */ $mail_to = "$to"; $from_mail = "Admin@********.co.uk"; $from_name = "*******Administrator"; $reply_to = "******.******@******.com"; $subject = "$subject"; $message = "$content"; /* Attachment File */ // Attachment location $file_name = "prebrief.pdf"; $path = ""; // Read the file content $file = $path.$file_name; $file_size = filesize($file); $handle = fopen($file, "r"); $att = fread($handle, $file_size); fclose($handle); $att = chunk_split(base64_encode($att)); /* Set the email header */ // Generate a boundary $boundary = md5(uniqid(time())); // Email header $header = "From: ".$from_name." <".$from_mail.">\n"; $header .= "Reply-To: ".$reply_to."\n"; $header .= "MIME-Version: 1.0\n"; // Multipart wraps the Email Content and Attachment $header .= "Content-Type: multipart/mixed; boundary=\"".$boundary."\"\n"; $header .= "This is a multi-part message in MIME format.\n"; $header .= "--".$boundary."\n"; // Email content // Content-type can be text/plain or text/html $header .= "Content-type:text/html; charset=iso-8859-1\n"; $header .= "Content-Transfer-Encoding: 7bit\n"; $header .= "$message\n"; $header .= "--".$boundary."\n"; // Attachment // Edit content type for different file extensions $header .= "Content-Type: text/pdf;"; $header .="name=\"prebrief.pdf\"\n"; $header .= "Content-Disposition: attachment; filename=\"".$file_name."\"\r\n"; $header .= "Content-Transfer-Encoding:base64\r\n"; //$att= "<html><head><title></title></head><body>Test attachment for mail delivery</body></html>"; $header .= $att."\n\n"; $header .= "--".$boundary."--"; // Send email if (mail($mail_to, $subject, "", $header)) { echo "Sent"; } else { echo "Error"; } } Quote Link to comment https://forums.phpfreaks.com/topic/259262-email-with-attachemnt/#findComment-1329463 Share on other sites More sharing options...
Muddy_Funster Posted March 20, 2012 Share Posted March 20, 2012 ok, I've been through it and compared it to how my function looks, There was a lot of white space in the strings that shouldn't have been, some of the \n's were still \r\n, some lines didn't have enough \n's and you didn't wrap the charset value in double quotes, oh, and you missed out the To and Subject headers altogether (may only matter on some servers with a spam overwatch, but I put them in anyway). I think it should work now, if you want to see my function for comparison it's on my blog in my sig, but here's the revised code anyway: <?php function emailJI($to, $subject, $attachment, $content){ /* Email Detials */ $mail_to = "$to"; $from_mail = "Admin@********.co.uk"; $from_name = "*******Administrator"; $reply_to = "******.******@******.com"; $subject = "$subject"; $message = "$content"; /* Attachment File */ // Attachment location $file_name = "prebrief.pdf"; $path = ""; // Read the file content $file = $path.$file_name; $file_size = filesize($file); $handle = fopen($file, "r"); $att = fread($handle, $file_size); fclose($handle); $att = chunk_split(base64_encode($att)); /* Set the email header */ // Generate a boundary $boundary = md5(uniqid(time())); // Email header $header = "From: ".$from_name." <".$from_mail.">\n"; $header .= "To: ".$mail_to."\n"; $header .= "Subject: ".$subject."\n"; $header .= "Reply-To: ".$reply_to."\n"; $header .= "MIME-Version: 1.0\n"; // Multipart wraps the Email Content and Attachment $header .= "Content-Type: multipart/mixed;boundary=\"".$boundary."\"\n\n"; $header .= "This is a multi-part message in MIME format.\n"; $header .= "--".$boundary."\n"; // Email content // Content-type can be text/plain or text/html $header .= "Content-type:text/html;charset=\"iso-8859-1\";\n"; $header .= "Content-Transfer-Encoding:7bit\n\n\n"; $header .= "$message\n\n"; $header .= "--".$boundary."\n"; // Attachment // Edit content type for different file extensions $header .= "Content-Type:text/pdf;"; $header .="name=\"prebrief.pdf\"\n"; $header .= "Content-Disposition:attachment;filename=\"".$file_name."\"\n"; $header .= "Content-Transfer-Encoding:base64\n\n"; //$att= "<html><head><title></title></head><body>Test attachment for mail delivery</body></html>"; $header .= $att."\n\n"; $header .= "--".$boundary."--\n"; // Send email if (mail($mail_to, $subject, "", $header)) { echo "Sent"; } else { echo "Error"; } } ?> Sadly I can't test this just now as all mail traffic here is routed through the server and requires authentication. Good luck though, let me know how it goes. P.S. The reason you couldn't open the PDF when the transfer-encoding was commented out was because you still had it going through the base64 encode at the top of the function. Quote Link to comment https://forums.phpfreaks.com/topic/259262-email-with-attachemnt/#findComment-1329487 Share on other sites More sharing options...
Nodral Posted March 20, 2012 Author Share Posted March 20, 2012 Absolutely Brilliant!!!!!!!! Don't really understand what you did, but it works!!!!!!!!!! One further question. How would I attach more than one file? Quote Link to comment https://forums.phpfreaks.com/topic/259262-email-with-attachemnt/#findComment-1329492 Share on other sites More sharing options...
Muddy_Funster Posted March 20, 2012 Share Posted March 20, 2012 there are probably a couple of ways, but I would work with an array of values, content type, attachment name, file name, file, and then use a foreach to build the header to include each of them, you would have all these lines in the foreach: $header .= "--".$boundary."\n"; $header .= "Content-Type:text/pdf;"; //array value for content type after the : $header .="name=\"prebrief.pdf\"\n"; //array value for attachment name (remember file extension) $header .= "Content-Disposition:attachment;filename=\"".$file_name."\"\n"; //aray value for file name $header .= "Content-Transfer-Encoding:base64\n\n"; $header .= $att."\n\n"; //aray value for file Quote Link to comment https://forums.phpfreaks.com/topic/259262-email-with-attachemnt/#findComment-1329500 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.