Hi!

I've desperately tried to find what's wrong with the following code:

    $file = $path.$filename;
    $file_size = filesize($file);
    $handle = fopen($file, "r");

$content_attachment = fread($handle, $file_size);
$type = mime_content_type($file);
fclose($handle);

$content_attachment = chunk_split(base64_encode($content_attachment));
$uid = md5(uniqid(time()));
$name = basename($file);

$header = "From: ".$from_name." <".$from_mail.">\r\n";
$header .= "Reply-To: ".$replyto."\r\n";
$header .= "MIME-Version: 1.0\r\n\r\n";
$header .= "Content-Type: multipart/mixed; boundary=\"".$uid."\"\r\n\r\n";

$content = "This is a multi-part message in MIME format.\r\n\r\n";
$content .= "--".$uid."\r\n";
$content .= "Content-Type:text/plain; charset=iso-8859-1\r\n";
$content .= "Content-Transfer-Encoding: 7bit\r\n\r\n";
$content .= $message."\r\n\r\n";
$content .= "--".$uid."\r\n";
$content .= "Content-Type: $type; name=\"".$filename."\"\r\n"; 
$content .= "Content-Transfer-Encoding: base64\r\n\r\n";
$content .= "Content-Disposition: attachment; filename=\"".$filename."\"\r\n\r\n";
$content .= $content_attachment."\r\n\r\n";
$content .= "--".$uid."--";

   if (mail($mailto, $subject, $content, $header)) {
        echo "mail send ... OK"; // or use booleans here
    } 
    else {
        echo "mail send ... ERROR!";
    }

It works perfectly when I comment the multipart/mixed part, but as soon as I take it in and if it's only this one line ($header .= "Content-Type: multipart/mixed; boundary=\"".$uid."\"\r\n\r\n"😉, it doesn't work any more... anybody any idea why?

Thanks for any replies!
Kyeema

    Welcome to PHPBuilder! When posting PHP code, please use the board's [noparse]

    ..

    [/noparse] bbcode tags as they make your code much easier to read and analyze.

    As for your error... look at the header you're adding just before the Content-Type header; because headers are separate from the content of the message by a double line break, you're preventing any further headers from being added. The double line break should only be appended after the last header in the group.

      Thanks for the fast reply and the info on headers!

      I removed the double crlf but unfortunately it still doesn't work... any other ideas?

      Again, thanks in advance!
      Kyeema

      Here again the corrected code:

          $file = $path.$filename;
          $file_size = filesize($file);
          $handle = fopen($file, "r");
      
      $content_attachment = fread($handle, $file_size);
      $type = mime_content_type($file);
      
      fclose($handle);
      
      $content_attachment = chunk_split(base64_encode($content_attachment));
      $uid = md5(uniqid(time()));
      $name = basename($file);
      
      $header = "From: ".$from_name." <".$from_mail.">\r\n";
      $header .= "Reply-To: ".$replyto."\r\n";
      $header .= "MIME-Version: 1.0\r\n";
      $header .= "Content-Type: multipart/mixed; boundary=\"".$uid."\"\r\n\r\n";
      
      $content = "This is a multi-part message in MIME format.\r\n\r\n";
      $content .= "--".$uid."\r\n";
      $content .= "Content-Type:text/plain; charset=iso-8859-1\r\n";
      $content .= "Content-Transfer-Encoding: 7bit\r\n\r\n";
      $content .= $message."\r\n\r\n";
      $content .= "--".$uid."\r\n";
      $content .= "Content-Type: $type; name=\"".$filename."\"\r\n"; 
      $content .= "Content-Transfer-Encoding: base64\r\n\r\n";
      $content .= "Content-Disposition: attachment; filename=\"".$filename."\"\r\n\r\n";
      $content .= $content_attachment."\r\n\r\n";
      $content .= "--".$uid."--";
      
      if (mail($mailto, $subject, $content, $header)) {
          echo "mail send ... OK"; // or use booleans here
      } 
         else {
              echo "mail send ... ERROR!";
          }
      

        I guess my first question (which I forgot to ask above) is... what does "doesn't work" mean? Does mail() return FALSE (and, if so, what is the PHP error message generated?), does the message not come through at all (did you check spam folders, if applicable?), does the message come through garbled (can you show us the raw content of the message received - any decent mail reader will offer this option), or ... ?

          I'm sorry of course I should have given details about what doesn't work...

          mail() returns false... the output ist "mail send... ERROR" of my if clause... that's the problem...

          And I don't get an error message - I called error_reporting(E_ALL)... gives me errors like "undefinded variable" when I comment the $content part, but nothing on the mail() function...

          😕

            Kyeema;10991246 wrote:

            gives me errors like "undefinded variable" when I comment the $content part

            Er... why would you comment out a vital part of the MIME message you're composing? Seems like that would almost be a guarantee that you're going to get errors in doing so.

            Kyeema;10991246 wrote:

            but nothing on the mail() function...

            Are you sure? If mail() returns FALSE, it almost always has an error message to output. Can you try setting error_reporting to E_ALL on the code you've posted above and then paste all PHP errors that you get?

            Finally, the only other tip I can think to offer would be to enable the mail.log PHP directive and see if PHP logs the message you're trying to send. If it does, it might help to examine the raw contents and see if everything looks correct.

              bradgrafelman;10991250 wrote:

              Er... why would you comment out a vital part of the MIME message you're composing? Seems like that would almost be a guarantee that you're going to get errors in doing so.

              Just for debugging reasons and to see which part of the code causes the mail() function not to work...

              Are you sure? If mail() returns FALSE, it almost always has an error message to output. Can you try setting error_reporting to E_ALL on the code you've posted above and then paste all PHP errors that you get?

              I did - this is the code I was last using for testing (echos are for debugging):

              	error_reporting(E_ALL);
                  $file = $path.$filename;
              	echo "Filename: ".$file."<br><br>";
                  $file_size = filesize($file);
              	echo "Filesize: ".$file_size."<br><br>";
                  $handle = fopen($file, "r");
              	echo "handle: ".$handle."<br><br>";
              
              $content_attachment = fread($handle, $file_size);
              echo "Content: ".$content_attachment."<br><br>";
              $type = mime_content_type($file);
              echo "Type: ".$type."<br><br>";
              
              fclose($handle);
              
              $content_attachment = chunk_split(base64_encode($content_attachment));
              $uid = md5(uniqid(time()));
              $name = basename($file);
              
              $header = "From: ".$from_name." <".$from_mail.">\r\n";
              $header .= "Reply-To: ".$replyto."\r\n";
              $header .= "MIME-Version: 1.0\r\n";
              $header .= "Content-Type: multipart/mixed; boundary=\"".$uid."\"\r\n\r\n";
              $content = "This is a multi-part message in MIME format.\r\n\r\n";
              $content .= "--".$uid."\r\n";
              $content .= "Content-Type:text/plain; charset=iso-8859-1\r\n";
              $content .= "Content-Transfer-Encoding: 7bit\r\n\r\n";
              $content .= $message."\r\n\r\n";
              $content .= "--".$uid."\r\n";
              $content .= "Content-Type: $type; name=\"".$filename."\"\r\n"; 
              $content .= "Content-Transfer-Encoding: base64\r\n\r\n";
              $content .= "Content-Disposition: attachment; filename=\"".$filename."\"\r\n\r\n";
              $content .= $content_attachment."\r\n\r\n";
              $content .= "--".$uid."--";
              echo $header."<br><br>".$mailto."<br><br>".$subject."<br><br>".$message."<br><br>".$content."<br><br>";
              if (mail($mailto, $subject, $content, $header)) {
                  echo "mail send ... OK"; // or use booleans here
              } 
              else {
                  echo "mail send ... ERROR!";
              }
              

              ... and this is the output I get (I replaced all contact/file data by xxx):

              &#65279;&#65279;Filename: Rechnungen/Rechnung_15.pdf

              Filesize: 934

              handle: Resource id #7

              Content: %PDF-1.3 3 0 obj <> endobj 4 0 obj <> stream x&#65533;3R&#65533;&#65533;2&#65533;35W(&#65533;r Q&#65533;w3T04&#65533;30PISp &#65533;Z&#65533;[&#65533;&#65533;&#65533;&#65533;(hx&#65533;&#65533;&#65533;&#65533;+&#65533;&#65533;&#65533;(j&#65533;d&#65533;&#65533;7W endstream endobj 1 0 obj <> endobj 5 0 obj <> endobj 2 0 obj << /ProcSet [/PDF /Text /ImageB /ImageC /ImageI] /Font << /F1 5 0 R >> /XObject << >> >> endobj 6 0 obj << /Producer (FPDF 1.53) /CreationDate (D:20111115075212) >> endobj 7 0 obj << /Type /Catalog /Pages 1 0 R /OpenAction [3 0 R /FitH null] /PageLayout /OneColumn >> endobj xref 0 8 0000000000 65535 f 0000000228 00000 n 0000000416 00000 n 0000000009 00000 n 0000000087 00000 n 0000000315 00000 n 0000000520 00000 n 0000000596 00000 n trailer << /Size 8 /Root 7 0 R /Info 6 0 R >> startxref 699 %%EOF

              Type: application/pdf

              From: xxx Admin Reply-To: xxxx@xxx.com MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="9ad2657bd90faecb5c38ac8fcc202e84"

              xxxx@xxxx.com

              Test

              Test2

              This is a multi-part message in MIME format. --9ad2657bd90faecb5c38ac8fcc202e84 Content-Type:text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 7bit Test2 --9ad2657bd90faecb5c38ac8fcc202e84 Content-Type: application/pdf; name="xxx.pdf" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="xxx.pdf" JVBERi0xLjMKMyAwIG9iago8PC9UeXBlIC9QYWdlCi9QYXJlbnQgMSAwIFIKL1Jlc291cmNlcyAy IDAgUgovQ29udGVudHMgNCAwIFI+PgplbmRvYmoKNCAwIG9iago8PC9GaWx0ZXIgL0ZsYXRlRGVj b2RlIC9MZW5ndGggNzI+PgpzdHJlYW0KeJwzUvDiMtAzNVco53IKUdB3M1QwNNMzMFAISVNwDQEJ GRvqGVoqmFuagBSFpChoeKTm5OQrhOcX5aQoaiqEZIHUAQAXNxBXCmVuZHN0cmVhbQplbmRvYmoK MSAwIG9iago8PC9UeXBlIC9QYWdlcwovS2lkcyBbMyAwIFIgXQovQ291bnQgMQovTWVkaWFCb3gg WzAgMCA1OTUuMjggODQxLjg5XQo+PgplbmRvYmoKNSAwIG9iago8PC9UeXBlIC9Gb250Ci9CYXNl Rm9udCAvSGVsdmV0aWNhLUJvbGQKL1N1YnR5cGUgL1R5cGUxCi9FbmNvZGluZyAvV2luQW5zaUVu Y29kaW5nCj4+CmVuZG9iagoyIDAgb2JqCjw8Ci9Qcm9jU2V0IFsvUERGIC9UZXh0IC9JbWFnZUIg L0ltYWdlQyAvSW1hZ2VJXQovRm9udCA8PAovRjEgNSAwIFIKPj4KL1hPYmplY3QgPDwKPj4KPj4K ZW5kb2JqCjYgMCBvYmoKPDwKL1Byb2R1Y2VyIChGUERGIDEuNTMpCi9DcmVhdGlvbkRhdGUgKEQ6 MjAxMTExMTUwNzUyMTIpCj4+CmVuZG9iago3IDAgb2JqCjw8Ci9UeXBlIC9DYXRhbG9nCi9QYWdl cyAxIDAgUgovT3BlbkFjdGlvbiBbMyAwIFIgL0ZpdEggbnVsbF0KL1BhZ2VMYXlvdXQgL09uZUNv bHVtbgo+PgplbmRvYmoKeHJlZgowIDgKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAwMjI4IDAw MDAwIG4gCjAwMDAwMDA0MTYgMDAwMDAgbiAKMDAwMDAwMDAwOSAwMDAwMCBuIAowMDAwMDAwMDg3 IDAwMDAwIG4gCjAwMDAwMDAzMTUgMDAwMDAgbiAKMDAwMDAwMDUyMCAwMDAwMCBuIAowMDAwMDAw NTk2IDAwMDAwIG4gCnRyYWlsZXIKPDwKL1NpemUgOAovUm9vdCA3IDAgUgovSW5mbyA2IDAgUgo+ PgpzdGFydHhyZWYKNjk5CiUlRU9GCg== --9ad2657bd90faecb5c38ac8fcc202e84--

              mail send ... ERROR!

              Finally, the only other tip I can think to offer would be to enable the mail.log PHP directive and see if PHP logs the message you're trying to send. If it does, it might help to examine the raw contents and see if everything looks correct.

              I'm sorry, please don't laugh at me but how do I do that? I don't have access to php.ini...

              Thanks again for helping me! 😃

                You still have double CRLFs in the middle of your headers. Each and every individual part which contains mail headers must have those headers follow the same rules as the headers of the overall message. Thus, remove the extra CRLFs.

                You do not seem to define $message anywhere, yet you

                $content .= $message
                

                And also, even though you append (the undefined) $message to $content, you also include $message here

                echo $header."<br><br>".$mailto."<br><br>".$subject."<br><br>".$message."<br><br>".$content."<br><br>"; 
                

                Also note that, as specified by RFC1341

                NOTE: These "preamble" and "epilogue" areas are not used because of the lack of proper typing of these parts and the lack of clear semantics for handling these areas at gateways, particularly X.400 gateways.

                The preamble area is the part before the first boundary, and the epilogue area is the part following the ending boundary.

                $header .= "Content-Type: multipart/mixed; boundary=\"".$uid."\"\r\n\r\n";
                # In other words, this line should be removed
                $content = "This is a multi-part message in MIME format.\r\n\r\n";
                # Warning: removing the above line will cause the boundary here to NOT
                # be preceeded by CRLF, which it must. See below for a suggestion
                $content .= "--".$uid."\r\n";
                

                Since the RFC also specifies that a boundary is always preceeded by CRLF, I prefer adding that to the actual variable used for the boundaries separating each part to avoid issues if the body of a particular part doesn't end with one or more CRLFs. I.e.

                $uid = md5(uniqid(time()));
                $boundary = "\r\n--$uid";
                # snip
                $header .= "Content-Type: multipart/mixed; boundary=\"".$uid."\"\r\n\r\n";
                # When removing this line, or if it didn't end with at least one CRLF
                $content = "This is a multi-part message in MIME format.";
                # ... you'd still be safe since $boundary now includes a prepended CRLF
                $content .= $boundary;
                

                  Thanks! 😃

                  I removed ALL double CRLF except for the ones before the boundary and the email gets sent! Yes!

                  Stupid me, I thought $content was handled differently...

                  Next trouble on my horizon: the message is not displayed ($message is a function parameter like the rest of my vars, its value is Test2) and the pdf can't be opened, I get the message it's not a valid file type or damaged, but now I have something I can work with...

                  Thanks again.... and any ideas are still welcome... 🙂

                    Have you tried opening the file before sending it so the file isn't actually corrupt? What's your current code?

                      YES! 😃 I found the error and now it works...

                      I had to insert some CRLFs again (one before adding $message to the string and another before adding the attachment contents)...

                      I have to admit I still don't get it really when to add double CRLFs and where not... and I haven't found a good tutorial so far, I'm just experimenting... :eek:

                      But I tested it again - now the script is the same as in the beginning, the only double CRLF I really had to delete was the one after

                      "Content-Type: multipart/mixed; boundary=\"".$uid."\"\r\n"

                      ... this is the place where only one CRLF is allowed... the rest doesn't really matter as it seems...

                      Hope this helps someone else too...

                      Thanks again for all your help here... naq rawbl! 😃

                      Here again the full script that finally works:

                          $file = $path.$filename;
                          $file_size = filesize($file);
                      	$type = mime_content_type($file);
                      
                      $handle = fopen($file, "r");
                      $content_attachment = fread($handle, $file_size);
                      fclose($handle);
                      
                      $content_attachment = chunk_split(base64_encode($content_attachment));
                      $uid = md5(uniqid(time()));
                      $name = basename($file);
                      
                      $header = "From: ".$from_name." <".$from_mail.">\r\n";
                      $header .= "Reply-To: ".$replyto."\r\n";
                      $header .= "MIME-Version: 1.0\r\n";
                      $header .= "Content-Type: multipart/mixed; boundary=\"".$uid."\"\r\n";
                      
                      $content = "\r\n--".$uid."\r\n";
                      $content .= "Content-Type:text/plain; charset=iso-8859-1\r\n";
                      $content .= "Content-Transfer-Encoding: 7bit\r\n\r\n";
                      $content .= $message."\r\n";
                      
                      $content .= "\r\n--".$uid."\r\n";
                      $content .= "Content-Type: $type; name=\"".$filename."\"\r\n"; 
                      $content .= "Content-Transfer-Encoding: base64\r\n";
                      $content .= "Content-Disposition: attachment; filename=\"".$filename."\"\r\n\r\n";
                      $content .= $content_attachment."\r\n";
                      $content .= "\r\n--".$uid."--";
                      
                      if (mail($mailto, $subject, $content, $header)) {
                          echo "mail send ... OK"; 
                      } 
                      else {
                          echo "mail send ... ERROR!";
                      }
                      
                        Kyeema;10991297 wrote:

                        I have to admit I still don't get it really when to add double CRLFs and where not... and I haven't found a good tutorial so far, I'm just experimenting... :eek:

                        There's not really a need for a tutorial in the matter, just the relevant RFCs. While RFC822, which was the initial RFC defining the MIME structure, has been extended, it should be enough to read it for the purpose of learning how the overall structure of messages should be. Should you need more information, search for MIME on wikipedia and you'll find links to relevant RFCs.

                        Anyway, a quick look at RFC 822, section 3.2: Header field definitions

                        field = field-name ":" [ field-body ] CRLF

                         field-name  =  1*<any CHAR, excluding CTLs, SPACE, and ":">
                        
                         field-body  =  field-body-contents
                                        [CRLF LWSP-char field-body]
                        
                         field-body-contents =
                                       <the ASCII characters making up the field-body, as
                                        defined in the following sections, and consisting
                                        of combinations of atom, quoted-string, and
                                        specials tokens, or else consisting of texts>

                        For the purpose of CRLF, you pretty much only need to read the first line, which reads like this: A header field consists of field name (such as Content-Type) followed by : followed by field body (such as text/plain) followed by CRLF. Not devling deeper into things, that's almost everything you need to know about email headers: Each email header is terminated by one CRLF.

                        The following lines specify what a field name should look like and what the field body should look like. These lines specify that "folding", CRLF followed by leading whitespace (LWSP), is allowed for the field body. Folding is explaing elsewhere in the RFC, but what it means is that you can break up one header over multiple lines as long as you insert at least one LWSP directly after each such CRLF. It is only a CRLF not followed by LWSP that terminates the header field.

                        Which means that the following have the exact same meaning

                        Content-Type: text/plain; charset=utf-8
                        
                        Content-Type: text/plain;
                           charset=utf-8
                        

                        Moving on to section 4: Message syntax

                        message = fields ( CRLF text ) ; Everything after
                        ; first null line
                        ; is message body

                        which should be read like this: A message consists of header fields optionally followed by (CRLF optionally followed by text). That is, if there is a message body (the text), there should be a CRLF between the headers and the body. Now, since you allready know that a header is terminated by a CRLF (that is, the CRLF terminating one header field actually belongs to that header field), it follows that there will always be 2 CRLF before the message body: one to terminate the last header field and one preceeding the message body.

                          Thanks a lot for the detailed explanation! 🙂

                          I know it doesn't change the function of the script, but to make it also logically correct to read, it would have to look like this, doesn't it?

                              $file = $path.$filename;
                              $file_size = filesize($file);
                              $type = mime_content_type($file);
                          
                          $handle = fopen($file, "r");
                          $content_attachment = fread($handle, $file_size);
                          fclose($handle);
                          
                          $content_attachment = chunk_split(base64_encode($content_attachment));
                          $uid = md5(uniqid(time()));
                          $name = basename($file);
                          
                          $header = "From: ".$from_name." <".$from_mail.">\r\n";
                          $header .= "Reply-To: ".$replyto."\r\n";
                          $header .= "MIME-Version: 1.0\r\n";
                          $header .= "Content-Type: multipart/mixed; boundary=\"".$uid."\"\r\n";
                          
                          $content = "\r\n--".$uid."\r\n";
                          
                          $content .= "Content-Type:text/plain; charset=iso-8859-1\r\n";
                          $content .= "Content-Transfer-Encoding: 7bit\r\n";
                          $content .= "\r\n".$message."\r\n";
                          
                          $content .= "\r\n--".$uid."\r\n";
                          
                          $content .= "Content-Type: $type; name=\"".$filename."\"\r\n";
                          $content .= "Content-Transfer-Encoding: base64\r\n";
                          $content .= "Content-Disposition: attachment; filename=\"".$filename."\"\r\n";
                          $content .= "\r\n".$content_attachment."\r\n";
                          
                          $content .= "\r\n--".$uid."--";
                          
                          if (mail($mailto, $subject, $content, $header)) {
                              echo "mail send ... OK";
                          }
                          else {
                              echo "mail send ... ERROR!";
                          } 
                          

                          Am I right assuming that the boundary also has to start and end with CRLF like the message-body? Haven't found anything on multipart messages and boundaries in your link...

                          Thanks! 😃

                            Kyeema;10991349 wrote:

                            Am I right assuming that the boundary also has to start and end with CRLF like the message-body?
                            Haven't found anything on multipart messages and boundaries in your link...

                            Technically, the message bodies do not have to end with CRLF. The boundary MUST have a leading CRLF. Thus, if you have

                            I'm a message body
                            --boundary
                            

                            which we might express like this instead

                            I'm a message body[CRLF]--boundary
                            

                            You actually have a message body without trailing CRLF, since the CRLF present belongs to the boundary. If you want to end your message with a CRLF, you'd have two consecutive CRLFs.

                            See RFC 1341, section 7.2 for more info

                            Note that the encapsulation boundary must occur at the beginning of a line, i.e., following a CRLF, and that that initial CRLF is considered to be part of the encapsulation boundary rather than part of the preceding part. The boundary must be followed immediately either by another CRLF and the header fields for the next part, or by two CRLFs, in which case there are no header fields for the next part (and it is therefore assumed to be of Content-Type text/plain).

                              Thanks for taking your time and answering all my questions - you've helped me a lot! 😃

                                Write a Reply...