发送带附件的 PHP HTML 邮件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9519588/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 07:00:10  来源:igfitidea点击:

Send PHP HTML mail with attachments

phphtmlemailattachment

提问by Florian Müller

I got a problem: Until today, I sent HTML mails with PHP using a header which contains

我遇到了一个问题:直到今天,我使用 PHP 发送的 HTML 邮件使用包含

Content-type: text/html;

Now, I added functionality to add attachments. For this, I had to change this line to

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

Content-Type: multipart/mixed;

Now, with multipart/mixed, the rest of the mail, so the normal text, gets shown just as text/plain. How can I realize that attachments work and the mailtext is still HTML?

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

采纳答案by Sanjay Prajapati

To send an email with attachment we need to use the multipart/mixed MIME type that specifies that mixed types will be included in the email. Moreover, we want to use multipart/alternative MIME type to send both plain-text and HTML version of the email.Have a look at the example:

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

<?php 
//define the receiver of the email 
$to = '[email protected]'; 
//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: [email protected]\r\nReply-To: [email protected]"; 
//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"; 
?>

As you can see, sending an email with attachment is easy to accomplish. In the preceding example we have multipart/mixed MIME type, and inside it we have multipart/alternative MIME type that specifies two versions of the email. To include an attachment to our message, we read the data from the specified file into a string, encode it with base64, split it in smaller chunks to make sure that it matches the MIME specifications and then include it as an attachment.

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

回答by Brian

I tried Answer 1 for a couple of hours with no luck. I found a solution here: http://www.finalwebsites.com/forums/topic/php-e-mail-attachment-script

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

Works like a charm- less than 5 min! You might want to change (like I did), the first content type from text/plain to text/html.

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

Here is my slightly modified version to handle multiple attachments:

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

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);
}

回答by Rayiez

SWIFTMAIL in php works gr8 for attachment with mails.

php 中的 SWIFTMAIL 适用于带有邮件的附件的 gr8。

Download swiftmailer from here http://swiftmailer.org/

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

Look at the simple code below

看下面的简单代码

INCLUDE FILE

包含文件

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

CREATE TRANSPORT

创建运输

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

OR

或者

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

MAILER OBJECT

邮件对象

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

CREATE MESSAGE OBJECT

创建消息对象

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

SEND MESSAGE

发信息

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

回答by Eugen Mihailescu

If you really want to learn how to format an Internet Message then you should refer its Request For Comments (aka RFC). The one that defines "Multipurpose Internet Mail Extensions - Format of Internet Message Bodies" is RFC2045issued on November 1996.

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

The format is somehow very strict and must be followed as-is.

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

Basically the message contains a header and the body. The header defines the type of the message, the way it's formated, some other fields which differ from one type to another.

基本上消息包含一个标题和正文。标头定义了消息的类型,它的格式化方式,以及从一种类型到另一种类型不同的一些其他字段。

The body is formed by different entities. An entity can be for instance just a plain-text like "Hello there!" but also can be an image, an attachment, whatever.

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

NOTEIn the following examples everything enclosed into brackets (eg. {hello}) should be replaced with your real value. Any newline is in reality CRLF (ie. ASCII 13 + ASCII 10). Where you see two CRLF stick to it. It would be the worst moment to show how creative you are.

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

Basically for an email message that has attachments the header should look like this:

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

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

In the above example the {mixed-boudary} may be any unique hash value, like 000008050800060107020705. The others are self-explanatory.

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

Now, anytime we want to append a new entity to the message (like the message body, an image, an attachment) we have to tell the email agent that a new section is coming, ie. to prefix that entity with the {mixed-boundary} value. We call this "open the boundary". Note that by opening a boundary we don't insert that boundary as was defined initially, we use 2 more minus signs in front, like --{mixed-boudary}. When we close a boundary we proceed likewise, except that we have to use other 2 minus signs at the end, like --{mixed-boudary}--

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

--{mixed-boudary}
the entity content
--{mixed-boudary}--

Because the email agent should understand what type has the content of our new inserted entity we have to declare that right after the opening of boundary. The declaration is just a header which contains only those parameters/values that are compatible with the entity.

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

For a HTML body content my entity header would look like:

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

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

so the whole body (enclosed into boundaries) will finally look like:

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

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

If another entity has to be inserted we proceed exactly like above. When there is no more data to add to the message we close the mixed-boundary, ie. CRLF + --{mixed-boudary}--.

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

If for any reason an entity has to be inserted with an alternative representation (eg. a body message is inserted both as plain-text format and also as HTML format), then the entity content has to be declared with content-type multipart/alternative (although the global multipart/mixed header still remains!). Each alternative representation will be enclosed by this new boundary.

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

A complete example below:

下面是一个完整的例子:

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

TIPS

Use your preferred email client (mine is Thunderbird) and send to yourself one message plain-text only, one HTML only, one mixed, and then each of the earlier but with one file attachment enclosed. When you receive the message just study its source (View -> Message source).

提示

使用您首选的电子邮件客户端(我的是 Thunderbird)并向自己发送一封纯文本消息,一封仅 HTML 邮件,一封混合邮件,然后每封邮件都包含一个文件附件。当您收到消息时,只需研究其来源(查看 -> 消息来源)。

@Edit: a very well documented case study + PHP example can be found at here

@Edit:可以在此处找到一个记录良好的案例研究 + PHP 示例