使用 PHP 在电子邮件中发送多个附件
Posted
技术标签:
【中文标题】使用 PHP 在电子邮件中发送多个附件【英文标题】:Sending multiple attachment in an email using PHP 【发布时间】:2015-03-01 16:57:25 【问题描述】:我在发送包含多个附件的电子邮件时遇到问题。代码如下:
<?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 . "\r\n";
$headers .= "Bcc:". $bcc . "\r\n";
// boundary
$semi_rand = md5(time());
$mime_boundary = "==Multipart_Boundary_x$semi_randx";
// 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 内容类型:多部分/混合; 边界="==Multipart_Boundary_x2d454346f03d2c19cfefc838ce4d8623x" 这是 MIME 格式的多部分消息。 --==Multipart_Boundary_x2d454346f03d2c19cfefc838ce4d8623x 内容类型:文本/html;字符集="iso-8859-1" 内容传输编码:7bit ds fsdfsdfsdfsdfsdfsdfsf sffdfsdfsdfs fsdfdf sdf s --==Multipart_Boundary_x2d454346f03d2c19cfefc838ce4d8623x Content-Type: "application/octet-stream";名称="/tmp/phpHFTvAw" 内容处置:附件;文件名="灯塔.jpg" 内容传输编码:base64 --==Multipart_Boundary_x2d454346f03d2c19cfefc838ce4d8623x Content-Type: "application/octet-stream";名称="/tmp/phpyX67HR" 内容处置:附件;文件名="企鹅.jpg" 内容传输编码:base64 --==Multipart_Boundary_x2d454346f03d2c19cfefc838ce4d8623x
【问题讨论】:
【参考方案1】:我建议使用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。
【讨论】:
感谢您的回答,但要求是仅使用邮件功能而不使用 phpmailer 发送电子邮件。【参考方案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:
标头使用\r\n
,这些可能应该使用相同的。您的输出还表明行尾可能丢失或格式错误。
来自PHP Manual:
如果未收到消息,请尝试仅使用 LF (\n)。一些 Unix 邮件传输代理(尤其是 » qmail)会自动将 LF 替换为 CRLF(如果使用 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 身体部分 *封装 闭合分隔符 [CRLF 结语] dash-boundary := "--" 边界 body-part := MIME-part-headers [CRLF *OCTET] 封装 := 分隔符 CRLF 身体部位 delimiter := CRLF 破折号边界 close-delimiter := 分隔符“--”
参考文献
【讨论】:
以上是关于使用 PHP 在电子邮件中发送多个附件的主要内容,如果未能解决你的问题,请参考以下文章