首页 文章

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

提问于
浏览
1

发送包含多个附件的电子邮件时遇到问题 . 这是代码:

<?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.'
'.$sub.'
'.$message.'

'; $from = 'test@gmail.com'; $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-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

2 回答

  • 2

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

    <?php
    
    require 'PHPMailerAutoload.php';                      // If this file is not located in the same directory, use __DIR__ . "/path/to/PHPMailerAutoload.php"
    
    $mail = new PHPMailer;
    
    $mail->From = 'from@example.com';
    $mail->FromName = 'Mailer';
    $mail->addAddress('joe@example.net', 'Joe User');     // Add a recipient
    $mail->addAddress('ellen@example.com');               // Name is optional
    $mail->addReplyTo('info@example.com', 'Information');
    $mail->addCC('cc@example.com');
    $mail->addBCC('bcc@example.com');
    
    $mail->addAttachment('/var/tmp/file.tar.gz');         // Add attachments
    $mail->addAttachment('/tmp/image.jpg', 'new.jpg');    // Optional name
    $mail->isHTML(true);                                  // Set email format to HTML
    
    $mail->Subject = 'Here is the subject';
    $mail->Body    = 'This is the HTML message body <b>in bold!</b>';
    $mail->AltBody = 'This is the body in plain text for non-HTML mail clients';
    
    if(!$mail->send()) {
        echo 'Message could not be sent.';
        echo 'Mailer Error: ' . $mail->ErrorInfo;
    } else {
        echo 'Message has been sent';
    }
    
    ?>
    

    下载和文档:here .

  • 2

    答案

    我在下面详细介绍了您的代码存在的一些问题 .

    行结尾

    $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: Headers 正在使用 \r\n ,这些应该使用相同的 . 您的输出还表明行结尾可能丢失或格式错误 .

    PHP Manual

    如果未收到消息,请尝试仅使用LF(\ n) . 一些Unix邮件传输代理(最明显的是»qmail)自动替换CRLF的LF(如果使用CRLF,则会导致CR加倍) . 这应该是最后的手段,因为它不符合»RFC 2822 .

    标头语法

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

    删除大括号和引号:

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

    此外,不推荐使用 name 参数,而是使用 Content-Disposition 标头中的 filename 参数 . 如果要保持它的向后兼容性,则应从中删除路径 . (您的输出表明您使用的是 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:= [序言CRLF]
    短划线CRLF
    body-part * encapsulation
    特写分隔符
    [CRLF结语]

    破折号边界:=“ - ”边界

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

    封装:=分隔符
    CRLF身体部位

    分隔符:= CRLF破折号边界

    close-delimiter:= delimiter“ - ”

    参考文献

相关问题