使用PHP在电子邮件中发送多个附件

问题描述 投票:2回答:2

我在发送带有多个附件的电子邮件时遇到问题。这是代码:

<?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 = '[email protected]';
                $sub = $_POST['subject'];
                $message = $_POST['message'];

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


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

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

                // multipart boundary 
                $message = "This is a multi-part message in MIME format.\n\n" . "--{$mime_boundary}\n" . "Content-Type: text/html; charset=\"iso-8859-1\"\n" . "Content-Transfer-Encoding: 7bit\n\n" . $message . "\n\n"; 
                $message .= "--{$mime_boundary}\n";

                // 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\"};\n" . " name=\"$files[$x]\"\n" . 
                    "Content-Disposition: attachment;\n" . " filename=\"$files[$x]\"\n" . 
                    "Content-Transfer-Encoding: base64\n\n" . $data . "\n\n";
                    $message .= "--{$mime_boundary}\n";
                }

                    // 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>

我收到了邮件,但找不到任何附件。有人知道什么地方可能出问题吗?

这是我收到邮件的电子邮件正文:

MIME版本:1.0内容类型:多部分/混合;boundary =“ == Multipart_Boundary_x2d454346f03d2c19cfefc838ce4d8623x”这是MIME格式的多部分消息。-== Multipart_Boundary_x2d454346f03d2c19cfefc838ce4d8623x内容类型:text / html; charset =“ iso-8859-1”内容传输编码:7bitds fsdfsdfsdfsdfsdfsdfsf sffdfsdfsdfs fsdfdf sdf s-== Multipart_Boundary_x2d454346f03d2c19cfefc838ce4d8623x内容类型:{“ application / octet-stream”}; name =“ / tmp / phpHFTvAw”内容处置:附件; filename =“ Lighthouse.jpg”内容传输编码:base64-== Multipart_Boundary_x2d454346f03d2c19cfefc838ce4d8623x内容类型:{“ application / octet-stream”}; name =“ / tmp / phpyX67HR”内容处置:附件; filename =“ Penguins.jpg”内容传输编码:base64-== Multipart_Boundary_x2d454346f03d2c19cfefc838ce4d8623x
php email email-attachments
2个回答
4
投票

答案

您的代码有一些问题,我在下面详细介绍。

  • 行尾

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

    电子邮件中的行由CRLF\r\n)序列分隔。尚不清楚mail()函数是否将\n转换为\r\n,但是考虑到您的From:Bcc:标头正在使用\r\n,这些标头可能应该使用相同的名称。您的输出还表明行尾可能丢失或格式不正确。

    PHP Manual

    如果未收到消息,请尝试仅使用LF(\ n)。一些Unix邮件传输代理(最著名的是» qmail)会自动用CRLF替换LF(如果使用CRLF,则会导致CR翻倍)。这应该是不得已的方法,因为它不符合» RFC 2822
  • Header语法

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

    删除括号和引号:

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

    [此外,name参数已被弃用,以filename标头中的Content-Disposition参数为好。如果要保持其向后兼容性,则应从中删除路径。 (您的输出表明您使用的是tmp_name,而不是name。)>

  • 分隔符

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

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

请注意,最后一个定界符必须带有两个尾划线。在循环的开头插入分隔定界符,并在循环之后添加一个封闭的定界符:

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

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

请参见下面有关电子邮件语法的部分。

  • 行长

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

    请注意,电子邮件中有行长限制。 RFC 5322

    ...每行字符不得超过998个字符,且不得超过78个字符(不包括)CRLF。

    您可能想减少Bcc的缩写或引入FWS (Folding White Space)

    $bcc .= $toEmails[$i].",\r\n ";  /* FWS */
    
  • 其他问题

  • 一些可能有用或可能无效的其他问题或通知:


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

    最后一行与:

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

    我假设$target_path应该初始化为上载目录。


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

    通常,您不应该允许随机用户提供外发电子邮件地址,但是我怀疑这是受信任用户的内部应用程序。


    电子邮件语法

    这是根据RFC 2046的多部分消息主体的结构的摘录。(BNF语法,有所简化。]

    multipart-body:= [preamble CRLF]虚线边界CRLF身体部位*封装封闭定界符[CRLF结语]虚线边界:=“-”边界正文部分:= MIME部分标头[CRLF * OCTET]封装:=分隔符CRLF身体部位分隔符:= CRLF虚线边界close-delimiter:=分隔符“-”

    参考


    3
    投票

    我建议使用PHPMailer发送带有附件的邮件:

    © www.soinside.com 2019 - 2024. All rights reserved.