Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
251 views
in Technique[技术] by (71.8m points)

Sending multiple attachment in an email using PHP

I have problem sending an email with multiple attachments. Here is the code:

<?php

    if(isset($_POST['sendEmail']))
    {

        foreach($_FILES['uploadEmail']['error'] as $key=>$value){
            if(!$_FILES['uploadEmail']['error'][$key]){
                $target_path = "";
                $target_path = $target_path . basename( $_FILES['uploadEmail']['name'][$key]); 
                if(move_uploaded_file($_FILES['uploadEmail']['tmp_name'][$key], $target_path)){
                    $files[] = $_FILES['uploadEmail']['name'][$key];
                }
            }
        }

        $toEmails = explode(",",$_POST['toEmail']);
        $count = count($toEmails);
        $i = 0;    $j = 1;    $k = 100;
        $bcc = '';
        while($i<$count){
            $bcc .= $toEmails[$i].",";
            if($j==$k || $i==$count-1){
                $j=1;
                //echo $bcc.'<br />'.$sub.'<br />'.$message.'<br /><br />';
                $from = 'test@gmail.com';
                $sub = $_POST['subject'];
                $message = $_POST['message'];

                /////////////////////////
                $headers = 'From:'. $from . "
";
                $headers .= "Bcc:". $bcc . "
";


                // boundary 
                $semi_rand = md5(time()); 
                $mime_boundary = "==Multipart_Boundary_x{$semi_rand}x"; 

                // headers for attachment 
                $headers .= "
MIME-Version: 1.0
" . "Content-Type: multipart/mixed;
" . " boundary="{$mime_boundary}""; 

                // multipart boundary 
                $message = "This is a multi-part message in MIME format.

" . "--{$mime_boundary}
" . "Content-Type: text/html; charset="iso-8859-1"
" . "Content-Transfer-Encoding: 7bit

" . $message . "

"; 
                $message .= "--{$mime_boundary}
";

                // preparing attachments
                for($x=0;$x<count($files);$x++){
                    $file = fopen($files[$x],"rb");
                    //echo "<br>".filesize($files[$x]);
                    $data = fread($file,filesize($files[$x]));
                    fclose($file);
                    $data = chunk_split(base64_encode($data));
                    $message .= "Content-Type: {"application/octet-stream"};
" . " name="$files[$x]"
" . 
                    "Content-Disposition: attachment;
" . " filename="$files[$x]"
" . 
                    "Content-Transfer-Encoding: base64

" . $data . "

";
                    $message .= "--{$mime_boundary}
";
                }

                    // send
                    /////////////////////////

                mail('',$sub,$message,$headers);
                $bcc = '';
            }else{
                $j++;
            }
            $i++;
        }
    }
?>
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js"></script>

<script src="http://js.nicedit.com/nicEdit-latest.js" type="text/javascript"></script>
<script type="text/javascript">bkLib.onDomLoaded(function() {
        new nicEditor().panelInstance('message');
       // new nicEditor({fullPanel : true}).panelInstance('area2');
  });</script>
</head>
<body>
<form method="POST" enctype="multipart/form-data">
    <table>
        <tr><td><label for="toEmail">Send To : </label></td><td><textarea id="toEmail" name="toEmail" cols="100" rows="10"></textarea></td></tr>
        <tr><td><label for="subject">Subject : </label></td><td><input type="text" name="subject" id="subject" size="98"></td></tr>
        <tr><td><label for="toEmail">Message : </label></td><td><textarea id="message" name="message" cols="100" rows="10"></textarea></td></tr>
        <tr><td><label for="upload[]">Attachments:</label></td><td></td></tr>
        <tr><td><label>1</label></td><td><input type="file" name="uploadEmail[]"></td></tr>
        <tr><td><label>2</label></td><td><input type="file" name="uploadEmail[]"></td></tr>
        <tr><td><label>3</label></td><td><input type="file" name="uploadEmail[]"></td></tr>
        <tr><td><label>4</label></td><td><input type="file" name="uploadEmail[]"></td></tr>
        <tr><td><label>5</label></td><td><input type="file" name="uploadEmail[]"></td></tr>
        <tr><td><label>6</label></td><td><input type="file" name="uploadEmail[]"></td></tr>
        <tr><td><label>7</label></td><td><input type="file" name="uploadEmail[]"></td></tr>
        <tr><td><label>8</label></td><td><input type="file" name="uploadEmail[]"></td></tr>
        <tr><td><label>9</label></td><td><input type="file" name="uploadEmail[]"></td></tr>
        <tr><td><label>10</label></td><td><input type="file" name="uploadEmail[]"></td></tr>
        <tr><td colspan="2" align="center"><input type="submit" value="Send Email" name="sendEmail" id="sendEmail"></td></tr>
    </table>
</form>
<body>
</html>

I received mail but could not find any attachments with it. Does anyone know what could be wrong?

Here is an email body which I got in mail:

MIME-Version: 1.0 Content-Type: multipart/mixed; 
boundary="==Multipart_Boundary_x2d454346f03d2c19cfefc838ce4d8623x"

This is a multi-part message in MIME format.

--==Multipart_Boundary_x2d454346f03d2c19cfefc838ce4d8623x Content-Type: text/html; charset="iso-8859-1"
Content-Transfer-Encoding: 7bit

ds fsdfsdfsdfsdfsdfsdfsf sffdfsdfsdfs fsdfdf sdf s

--==Multipart_Boundary_x2d454346f03d2c19cfefc838ce4d8623x Content-Type: {"application/octet-stream"};  name="/tmp/phpHFTvAw"
Content-Disposition: attachment;  filename="Lighthouse.jpg"
Content-Transfer-Encoding: base64




--==Multipart_Boundary_x2d454346f03d2c19cfefc838ce4d8623x Content-Type: {"application/octet-stream"};  name="/tmp/phpyX67HR"
Content-Disposition: attachment;  filename="Penguins.jpg"
Content-Transfer-Encoding: base64




--==Multipart_Boundary_x2d454346f03d2c19cfefc838ce4d8623x
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Answer

There are a few problems with your code that I have detailed below.

  • Line endings

    $headers = 'From:'. $from . "
    ";
    $headers .= "Bcc:". $bcc . "
    ";
    
    ...
    
    // headers for attachment 
    $headers .= "
    MIME-Version: 1.0
    "
             .  "Content-Type: multipart/mixed;
    "
             .  " boundary="{$mime_boundary}""; 
    // multipart boundary 
    $message = "This is a multi-part message in MIME format.
    
    "
             . "--{$mime_boundary}
    "
             . "Content-Type: text/html; charset="iso-8859-1"
    "
             . "Content-Transfer-Encoding: 7bit
    
    "
             . $message
             . "
    
    "; 
    $message .= "--{$mime_boundary}
    ";
    

    Lines in email messages are separated by CRLF ( ) sequences. It is unclear whether the mail() function converts into or not, but considering that your From: and Bcc: headers are using , these should probably use the same. Your output also indicates that the line endings are possibly missing or malformed.

    From the PHP Manual:

    If messages are not received, try using a LF ( ) 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.
  • Header syntax

    $message .= "Content-Type: {"application/octet-stream"};
    "
             .  " name="$files[$x]"
    " . 
    

    Remove the braces and the quotes:

    $message .= "Content-Type: application/octet-stream
    "
             .  " name="$files[$x]"
    " . 
    

    Also, the name parameter has been deprecated in favour of the filename parameter in the Content-Disposition header. If you want to keep it for some backward compatibility, you should remove the path from it. (Your output indicates that you're using tmp_name rather than name).

  • Delimiters

    $message .= "--{$mime_boundary}
    ";
    
    // preparing attachments
    for($x=0;$x<count($files);$x++){
      ...
      $message .= /* body part */;
      $message .= "--{$mime_boundary}
    ";
    }
    

    Note that the final delimiter must have two trailing dashes. Insert the dividing delimiters at the beginning of the loop, and add a close delimiter after the loop:

    // preparing attachments
    for($x=0;$x<count($files);$x++){
      $message .= "--{$mime_boundary}
    ";
      ...
      $message .= /* body part */;
    }
    
    $message .= "--{$mime_boundary}--
    ";
    

    See the section on Email syntax below.

  • Line lengths

    $k = 100;
    ...
    while($i<$count){
      $bcc .= $toEmails[$i].",";
      if($j==$k || $i==$count-1){
        ...
        $headers .= "Bcc:". $bcc . "
    ";
    

    Note that there are line length limits in email messages. RFC 5322:

       ...                    Each line of characters MUST be no more than
       998 characters, and SHOULD be no more than 78 characters, excluding
       the CRLF.
    

    You may want to cut your Bcc's shorter or introduce FWS (Folding White Space):

    $bcc .= $toEmails[$i].",
     ";  /* FWS */
    
  • Other issues

    Some further issues or notices that might or might not be useful:


    foreach($_FILES['uploadEmail']['error'] as $key=>$value){
        if(!$_FILES['uploadEmail']['error'][$key]){
    

    The last line is the same as:

        if(!$value){
    

    $target_path = "";
    $target_path = $target_path . basename( $_FILES['uploadEmail']['name'][$key]); 
    

    I'm assuming that $target_path should be initialized to an upload directory.


    $toEmails = explode(",",$_POST['toEmail']);
    

    Generally, you should not allow random users to provide outgoing email addresses, but I suspect that this is an internal application for trusted users.


Email syntax

This is an excerpt of what the structure of a multi-part message body looks like according to RFC 2046. (BNF syntax, somewhat simplified.)

multipart-body := [preamble CRLF]
                  dash-boundary CRLF
                  body-part *encapsulation
                  close-delimiter
                  [CRLF epilogue]

dash-boundary := "--" boundary

body-part := MIME-part-headers [CRLF *OCTET]

encapsulation := delimiter
                 CRLF body-part

delimiter := CRLF dash-boundary

close-delimiter := delimiter "--"

References


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...