发送带附件的 PHP HTML 邮件

Posted

技术标签:

【中文标题】发送带附件的 PHP HTML 邮件【英文标题】:Send PHP HTML mail with attachments 【发布时间】:2012-03-20 03:31:47 【问题描述】:

我遇到了一个问题:直到今天,我使用 php 发送 html 邮件时使用的标题包含

Content-type: text/html;

现在,我添加了添加附件的功能。为此,我不得不将此行更改为

Content-Type: multipart/mixed;

现在,使用multipart/mixed,邮件的其余部分,即普通文本,将显示为 text/plain。我怎样才能意识到附件有效并且邮件文本仍然是 HTML?

【问题讨论】:

您的多部分邮件的每个部分都有自己的内容类型查看正确的多部分邮件的来源。 php send email with attachment 的可能副本。这里还有很多其他处理电子邮件和附件的,看看一些相关的。 在您的邮件模板中使用 MIME 标头 php.net/manual/en/function.mail.php where 查看 ANDA Anda 的帖子 05-Sep-2011 11:57 发送多附件电子邮件 为什么要重新发明***? PHP 有一个很棒的 PEAR 扩展来发送带有附件的邮件。 【参考方案1】:

我尝试了几个小时的答案 1,但没有成功。我在这里找到了解决方案: http://www.finalwebsites.com/forums/topic/php-e-mail-attachment-script

像魅力一样工作 - 不到 5 分钟!你可能想改变(像我一样),第一个内容类型从 text/plain 到 text/html。

这是我处理多个附件的稍微修改的版本:

function mail_attachment($files, $path, $mailto, $from_mail, $from_name, $replyto, $subject, $message) 
$uid = md5(uniqid(time()));

$header = "From: ".$from_name." <".$from_mail.">\r\n";
$header .= "Reply-To: ".$replyto."\r\n";
$header .= "MIME-Version: 1.0\r\n";
$header .= "Content-Type: multipart/mixed; boundary=\"".$uid."\"\r\n\r\n";
$header .= "This is a multi-part message in MIME format.\r\n";
$header .= "--".$uid."\r\n";
$header .= "Content-type:text/html; charset=iso-8859-1\r\n";
$header .= "Content-Transfer-Encoding: 7bit\r\n\r\n";
$header .= $message."\r\n\r\n";

    foreach ($files as $filename)  

        $file = $path.$filename;

        $file_size = filesize($file);
        $handle = fopen($file, "r");
        $content = fread($handle, $file_size);
        fclose($handle);
        $content = chunk_split(base64_encode($content));

        $header .= "--".$uid."\r\n";
        $header .= "Content-Type: application/octet-stream; name=\"".$filename."\"\r\n"; // use different content types here
        $header .= "Content-Transfer-Encoding: base64\r\n";
        $header .= "Content-Disposition: attachment; filename=\"".$filename."\"\r\n\r\n";
        $header .= $content."\r\n\r\n";
    

$header .= "--".$uid."--";
return mail($mailto, $subject, "", $header);

【讨论】:

这只是在...一些服务器遇到了问题 \r\n 并且附件和任何 html 都没有呈现。解决方法是在所有情况下都使用 PHP_EOL。就是这样。 我喜欢你的方法。但是我无法将 android APK 发送到平板电脑。好吧。它发送了 APK,但无法安装。 注意您的$path 需要在末尾有一个/,或者在$files 数组中所有$filename 的开头,并且文件名不能有空格,$file = $path.$filename; 更改为 $file = "$path/$filename"; 此外,此行毫无意义:$name = basename($file); 应删除。 我的路径变量标准是始终包含尾部斜杠,这是一个很好的观点。而且,是的,确实是您在其中发现的一行无关代码。 对于 PHP >=5.6,您需要将消息从标头中拆分出来,以避免出现 here 中提到的 Multiple or malformed newlines found in additional_header 错误。您还需要在第一个 Content-type 之后删除双 \r\n (但这可能是 PHP7 特定的......不确定)【参考方案2】:

要发送带附件的电子邮件,我们需要使用 multipart/mixed MIME 类型,指定混合类型将包含在电子邮件中。此外,我们希望使用 multipart/alternative MIME 类型来发送纯文本和 HTML 版本的电子邮件。请看示例:

<?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"; 
?>

如您所见,发送带有附件的电子邮件很容易完成。在前面的示例中,我们有 multipart/mixed MIME 类型,在其中我们有 multipart/alternative MIME 类型,它指定了电子邮件的两个版本。为了在消息中包含附件,我们将指定文件中的数据读入字符串,使用 base64 对其进行编码,将其拆分为更小的块以确保它符合 MIME 规范,然后将其作为附件包含。

【讨论】:

从其他来源复制粘贴时包含来源是正确的。我什至不知道这是否是来源,但他们的 cmets 可以追溯到 2007 年:webcheatsheet.com/php/send_email_text_html_attachment.php 是的,Sanjay 公然从另一个网站剪切和粘贴文本并且没有归属。【参考方案3】:

PHP 中的 SWIFTMAIL 使用 gr8 来作为邮件附件。

从这里下载 swiftmailer http://swiftmailer.org/

看下面的简单代码

包含文件

require_once('path/to/swiftMailer/lib/swift_required.php');

创建传输

//FOR SMTP
// Create the Transport
$transport = Swift_SmtpTransport::newInstance('smtp.googlemail.com', 465, 'ssl')
    ->setUsername('user@gmail.com')
    ->setPassword('gmailpassword');

//FOR NORMAL MAIL
$transport = Swift_MailTransport::newInstance();

邮件对象

// Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance($transport);

创建消息对象

$message = Swift_Message::newInstance($subject)
    ->setFrom(array($from => $from))
    ->setTo($to)
    ->setBody($body);
$message->attach(Swift_Attachment::fromPath($filepath));

发送消息

$result = $mailer->send($message);

【讨论】:

这个其实挺好看的,我去看看!谢谢:)【参考方案4】:

如果您真的想学习如何格式化 Internet 消息,那么您应该参考它的 Request For Comments(又名 RFC)。定义“多用途 Internet 邮件扩展 - Internet 消息正文的格式”的是 1996 年 11 月发布的RFC2045。

格式在某种程度上非常严格,必须按原样遵循。

基本上,消息包含标题和正文。标头定义了消息的类型、格式以及其他一些字段,这些字段因一种类型而异。

身体由不同的实体组成。例如,一个实体可以只是一个纯文本,例如“Hello there!”。但也可以是图像、附件等。

注意 在以下示例中,括号中的所有内容(例如 hello)都应替换为您的实际值。任何换行符实际上都是 CRLF(即 ASCII 13 + ASCII 10)。你在哪里看到两个 CRLF 坚持下去。这将是展示你的创造力的最糟糕的时刻。

基本上,对于带有附件的电子邮件,标题应如下所示:

MIME-Version: 1.0
To: email@domain
Subject: email-subject
X-Priority: 2 (High)
Content-Type: multipart/mixed; boundary="mixed-boudary"

在上面的示例中,mixed-boudary 可以是任何唯一的哈希值,例如 000008050800060107020705。其他的都是不言自明的。

现在,无论何时我们想要在邮件中添加一个新实体(如邮件正文、图像、附件),我们都必须告诉电子邮件代理一个新部分即将到来,即.用 mixed-boundary 值作为该实体的前缀。我们称之为“开放边界”。请注意,通过打开边界,我们不会像最初定义的那样插入该边界,而是在前面多使用 2 个减号,例如 --mixed-boudary。当我们关闭一个边界时,我们同样继续,除了我们必须在最后使用其他 2 个减号,比如 --mixed-boudary--

--mixed-boudary
the entity content
--mixed-boudary--

因为电子邮件代理应该了解我们新插入的实体的内容是什么类型,所以我们必须在边界打开后立即声明。声明只是一个标头,仅包含与实体兼容的参数/值。

对于 HTML 正文内容,我的实体标题如下所示:

Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: 7bit

所以整个身体(包围在边界中)最终看起来像:

--mixed-boudary
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: 7bit

<html>
<head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head>
<body bgcolor="#FFFFFF" text="#000000">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque vel 
dapibus arcu. Duis quam dui, ornare non mi nec, luctus faucibus massa. Vivamus 
quis purus in erat euismod ullamcorper vitae eget dolor. Aliquam tempor erat 
accumsan, consectetur ex et, rhoncus risus.
</body>
</html>

如果必须插入另一个实体,我们完全按照上面的方法进行。 当没有更多数据要添加到消息中时,我们关闭混合边界,即。 CRLF + --混合边界--.

如果出于任何原因必须使用替代表示插入实体(例如,正文消息以纯文本格式和 HTML 格式插入),则必须使用 content-type 声明实体内容multipart/alternative(尽管全局 multipart/mixed 标题仍然存在!)。每个替代表示都将被这个新边界包围。

下面是一个完整的例子:

MIME-Version: 1.0
To: email@domain
Subject: email-subject
X-Priority: 2 (High)
Content-Type: multipart/mixed; boundary="mixed-boudary"

--mixed-boudary
Content-Type: multipart/alternative; boundary="alternative-boudary"

--alternative-boudary
Content-Type: text/plain; charset=utf-8;
Content-Transfer-Encoding: 7bit

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque vel 
dapibus arcu. Duis quam dui, ornare non mi nec, luctus faucibus massa. Vivamus 
quis purus in erat euismod ullamcorper vitae eget dolor. Aliquam tempor erat 
accumsan, consectetur ex et, rhoncus risus.

--alternative-boudary
Content-Type: text/html; charset=utf-8;
Content-Transfer-Encoding: 7bit

<html>
<head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head>
<body bgcolor="#FFFFFF" text="#000000">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque vel 
dapibus arcu. Duis quam dui, ornare non mi nec, luctus faucibus massa. Vivamus 
quis purus in erat euismod ullamcorper vitae eget dolor. Aliquam tempor erat 
accumsan, consectetur ex et, rhoncus risus.
</body>
</html>

--alternative-boudary--

--mixed-boudary
Content-Type: application/pdf; name="myfile.pdf"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="myfile.pdf"

JVBERi0xLjINOCAwIG9iag08PCAvTGVuZ3RoIDkgMCBSIC9GaWx0ZXIgL0ZsYXRlRGVjb2Rl
ID4+DXN0cmVhbQ1oQ51bbY/cNg7+BfsfhAUO11w3riW/B7gPaZEAAdpcm06RL8EBzoyn68uM
vZ3xZLv//khKsuUxNaMNiiabpUg+pKiHsmxJEcN/UsgiilP4ab2/+XF1I81vszSqclHIOEpj
sdrf/PC2EFVUpmK1vXkZxVKs1uJlJJVYPYrvPra7XVvvxYdIrE7rL83hhVj97+bNyjUoFam7
FnOB+tubGI3FZEkwmhpKXpVRnqJi0PCyjBJ1DjyOYqWBxxXp/1h3X+ov9abZt434pV0feoG/
ars/xU/9/qEZmm7diJ+abmgOr0TGeFNFEuXx5M4B95Idns/QAaJMI1IpKeXi9+ZhaPafm4NQ
cRwzNpK0iirlRvisRBZpVJa+PP51091kkjBWBXrJxUuZRjIXh0Z8FN3MnB5X5st5Kay9355n

--mixed-boudary--

提示

使用您首选的电子邮件客户端(我的是 Thunderbird)并发送至 您自己 仅一条消息纯文本,一条仅 HTML,一条混合消息,以及 然后是较早的每个,但附有一个文件附件。什么时候 您收到消息只需研究其来源(查看 -> 消息 来源)。

@Edit:可以在here找到一个非常有据可查的案例研究 + PHP 示例

【讨论】:

以上是关于发送带附件的 PHP HTML 邮件的主要内容,如果未能解决你的问题,请参考以下文章

PHP - 发送带附件的电子邮件不显示邮件内容

PHP 发送带附件的多部分编码邮件。

Word邮件合并不能发送HTML格式以及怎么带附件?

[Java] JavaMail 发送 html 格式带附件的邮件

发送带附件的邮件

jquery 发送带附件的邮件