如何从 PHP 表单发送带有附件的电子邮件?

Posted

技术标签:

【中文标题】如何从 PHP 表单发送带有附件的电子邮件?【英文标题】:How can I send an email with attachments from a PHP form? 【发布时间】:2010-11-22 18:30:00 【问题描述】:

如何通过 php 表单发送带有附件的电子邮件?

【问题讨论】:

我不想打扰你,我提前为我的愚蠢道歉,但我想知道你问问题并自己回答的原因是什么?无论如何,+1 以获得好的答案 @ann_nikolo - 有朝一日帮助他人,可能还有我自己。如果我忘记了如何做某事,很高兴谷歌并找到我写的解释 - 我可能会理解它。 ;) 鼓励这样做:***.com/help/self-answer 【参考方案1】:

正如其他人在回答中所建议的那样,最好使用现有工具。但是,如果您想自己动手或只是了解如何操作,请继续阅读。

html

在您的 HTML 中发送文件附件实际上只有两个要求。

你的表单需要有这个属性:enctype="multipart/form-data" 您至少需要一个字段,例如<input type="file" name="examplefile">。这允许用户浏览要附加的文件。

如果您同时具备这两个条件,浏览器会将所有附件连同表单提交一起上传

旁注:这些文件在服务器上保存为临时文件。在本例中,我们将获取他们的数据并通过电子邮件发送,但如果您将临时文件移动到永久位置,则您只是创建了一个文件上传表单。

MIME 电子邮件格式

This tutorial 非常适合理解如何在 PHP 中构建 MIME 电子邮件(可以包含 HTML 内容、纯文本版本、附件等)。我以它为起点。

基本上,你会做三件事:

预先声明此电子邮件将包含多种类型的内容 声明一个用于分隔不同部分的文本字符串 定义每个部分并坚持适当的内容。对于文件附件,您必须指定类型并以 ASCII 对其进行编码。 每个部分都有一个content-type,例如image/jpgapplication/pdf. 更多信息可以在here 找到。 (我的示例脚本使用内置 PHP 函数从每个文件中提取这些信息。)

PHP

提交表单后,浏览器上传的任何文件(参见 HTML 部分)都将通过 $_FILES 变量提供,该变量包含“通过 HTTP POST 方法上传到当前脚本的项目的关联数组。 '

$_FILES 上的documentation 很糟糕,但是在上传之后,您可以运行print_r($_FILES) 来查看它是如何工作的。它会输出如下内容:

Array ( [examplefile] => Array ( [name] => your_filename.txt 
[type] => text/plain [tmp_name] => 
C:\path\to\tmp\file\something.tmp [error] => 0 [size] => 200 ) ) 

然后您可以使用file_get_contents($_FILES['examplefile']['tmp_name']) 获取相关临时文件中的数据。

关于文件大小限制的附注

php.ini 有一些限制附件大小的设置。请参阅this discussion 了解更多信息。

一个示例 PHP 函数

我创建了以下函数,该函数可以包含在页面中并用于收集通过表单提交的任何文件附件。随意使用它和/或根据您的需要调整它。

总附件限制是任意的,但大量可能会使mail() 脚本陷入困境或被发送或接收电子邮件服务器拒绝。进行自己的测试。

(注意:PHP 中的mail() 函数依赖于php.ini 中的信息来知道如何发送您的电子邮件。)

function sendWithAttachments($to, $subject, $htmlMessage)
  $maxTotalAttachments=2097152; //Maximum of 2 MB total attachments, in bytes
  $boundary_text = "anyRandomStringOfCharactersThatIsUnlikelyToAppearInEmail";
  $boundary = "--".$boundary_text."\r\n";
  $boundary_last = "--".$boundary_text."--\r\n";

  //Build up the list of attachments, 
  //getting a total size and adding boundaries as needed
  $emailAttachments = "";
  $totalAttachmentSize = 0;
  foreach ($_FILES as $file) 
    //In case some file inputs are left blank - ignore them
    if ($file['error'] == 0 && $file['size'] > 0)
      $fileContents = file_get_contents($file['tmp_name']);
      $totalAttachmentSize += $file['size']; //size in bytes
      $emailAttachments .= "Content-Type: " 
      .$file['type'] . "; name=\"" . basename($file['name']) . "\"\r\n"
      ."Content-Transfer-Encoding: base64\r\n"
      ."Content-disposition: attachment; filename=\"" 
      .basename($file['name']) . "\"\r\n"
      ."\r\n"
      //Convert the file's binary info into ASCII characters
      .chunk_split(base64_encode($fileContents))
      .$boundary;
    
  
  //Now all the attachment data is ready to insert into the email body.
  //If the file was too big for PHP, it may show as having 0 size
  if ($totalAttachmentSize == 0) 
    echo "Message not sent. Either no file was attached, or it was bigger than PHP is configured to accept.";
   
  //Now make sure it doesn't exceed this function's specified limit:
  else if ($totalAttachmentSize>$maxTotalAttachments) 
    echo "Message not sent. Total attachments can't exceed " .  $maxTotalAttachments . " bytes.";
  
  //Everything is OK - let's build up the email
  else     
    $headers =  "From: yourserver@example.com\r\n";
    $headers .=     "MIME-Version: 1.0\r\n"
    ."Content-Type: multipart/mixed; boundary=\"$boundary_text\"" . "\r\n";  
    $body .="If you can see this, your email client "
    ."doesn't accept MIME types!\r\n"
    .$boundary;

    //Insert the attachment information we built up above.
    //Each of those attachments ends in a regular boundary string    
    $body .= $emailAttachments;

    $body .= "Content-Type: text/html; charset=\"iso-8859-1\"\r\n"
    ."Content-Transfer-Encoding: 7bit\r\n\r\n"
    //Inert the HTML message body you passed into this function
    .$htmlMessage . "\r\n"
    //This section ends in a terminating boundary string - meaning
    //"that was the last section, we're done"
    .$boundary_last;

    if(mail($to, $subject, $body, $headers))
    
      echo "<h2>Thanks!</h2>Form submitted to " . $to . "<br />";
     else 
      echo 'Error - mail not sent.';
    
      

如果您想查看这里发生了什么,请注释掉对mail() 的调用,并让它将输出回显到您的屏幕上。

【讨论】:

我刚刚完成了所有这些工作,并想与其他人分享。如果有人可以提出改进建议,请执行!特别是错误处理可能不是很好。【参考方案2】:

为了发送实际的电子邮件,我建议使用PHPMailer library,它让一切变得更容易。

【讨论】:

发生了这个老问题,你的应该是官方答案。我认为现在是官方页面:github.com/PHPMailer/PHPMailer【参考方案3】:

不错tutorial here

代码

<?php
//define the receiver of the email
$to = 'youraddress@example.com';
//define the subject of the email
$subject = 'Test email with attachment';
//create a boundary string. It must be unique
//so we use the MD5 algorithm to generate a random hash
$random_hash = md5(date('r', time()));
//define the headers we want passed. Note that they are separated with \r\n
$headers = "From: webmaster@example.com\r\nReply-To: webmaster@example.com";
//add boundary string and mime type specification
$headers .= "\r\nContent-Type: multipart/mixed; boundary=\"PHP-mixed-".$random_hash."\"";
//read the atachment file contents into a string,
//encode it with MIME base64,
//and split it into smaller chunks
$attachment = chunk_split(base64_encode(file_get_contents('attachment.zip')));
//define the body of the message.
ob_start(); //Turn on output buffering
?>
--PHP-mixed-<?php echo $random_hash; ?> 
Content-Type: multipart/alternative; boundary="PHP-alt-<?php echo $random_hash; ?>"

--PHP-alt-<?php echo $random_hash; ?> 
Content-Type: text/plain; charset="iso-8859-1"
Content-Transfer-Encoding: 7bit

Hello World!!!
This is simple text email message.

--PHP-alt-<?php echo $random_hash; ?> 
Content-Type: text/html; charset="iso-8859-1"
Content-Transfer-Encoding: 7bit

<h2>Hello World!</h2>
<p>This is something with <b>HTML</b> formatting.</p>

--PHP-alt-<?php echo $random_hash; ?>--

--PHP-mixed-<?php echo $random_hash; ?> 
Content-Type: application/zip; name="attachment.zip" 
Content-Transfer-Encoding: base64 
Content-Disposition: attachment 

<?php echo $attachment; ?>
--PHP-mixed-<?php echo $random_hash; ?>--

<?php
//copy current buffer contents into $message variable and delete current output buffer
$message = ob_get_clean();
//send the email
$mail_sent = @mail( $to, $subject, $message, $headers );
//if the message is sent successfully print "Mail sent". Otherwise print "Mail failed"
echo $mail_sent ? "Mail sent" : "Mail failed";
?> 

【讨论】:

【参考方案4】:

您可能想查看SwiftMailer。它有一个不错的tutorial on this。

【讨论】:

以上是关于如何从 PHP 表单发送带有附件的电子邮件?的主要内容,如果未能解决你的问题,请参考以下文章

Mime 和 Office365

从表单发送电子邮件附件

如何使用带有附件的 PEAR Mail 包使用 PHP 发送电子邮件

PHP不发送带有附件的邮件

使用 S/MIME (PHP) 发送带有附件的电子邮件

PHP 发送带有 PDF 附件的电子邮件