多部分/混合内容类型被忽略。

3

我曾经写过一段代码来以硬编码的方式输出mime电子邮件,这非常容易。后来我创建了一个新的API来处理任何上下文,并且据我所知我复制并粘贴了相关的mime语法。然而,Gmail显示出来的是原始的mime格式。

我正在使用PHP的邮件功能。

以下代码是从Gmail的“显示原始邮件”中复制而来的,除了头部信息之外,与将电子邮件视为文本/纯文本查看时所看到的内容完全相同...我做错了什么?

Return-Path: <blah@blah.com>
Received: from www.blah.com (www.blah.com. [xxx.xx.xxx.xx])
        by mx.google.com with ESMTPSA id c8sm28269395qam.21.2014.07.15.16.54.29
        for <blah@blah.com>
        (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);
        Tue, 15 Jul 2014 16:54:29 -0700 (PDT)
Received: by www.blah.com (Postfix, from userid 27)
    id 7BF8B1CF2; Tue, 15 Jul 2014 19:54:28 -0400 (EDT)
To: blah@blah.com
Subject: blah blah blah
X-PHP-Originating-Script: 0:Blah.php
From: blah <blah@blah.com>
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="--=_NextPart_BIG_UUID_1"
Message-Id: <20140715225428.7BF8B1CF2@www.blah.com>
Date: Tue, 15 Jul 2014 18:54:28 -0400 (EDT)

----=_NextPart_BIG_UUID_1  
content-type: multipart/alternative; boundary="--=_NextAltPart_BIG_UUID_2"

----=_NextAltPart_BIG_UUID_2
content-type: text/plain; charset=iso-8859-1
content-transfer-encoding: quoted-printable

test text content 

----=_NextAltPart_BIG_UUID_2
content-type: multipart/related; boundary="--=_NextAltRelPart_BIG_UUID_3"

----=_NextAltRelPart_BIG_UUID_3
content-type: text/html; charset=UTF8
content-transfer-encoding: quoted-printable

<html><body><h1>BLAH</h1></body></html>

----=_NextAltRelPart_BIG_UUID_3
content-type: text/plain;
Content-transfer-encoding: base64
Content-ID: <whatever_doesnt_matter.txt>

dGVzdCBjb250ZW50


----=_NextAltRelPart_BIG_UUID_3--

----=_NextAltPart_BIG_UUID_2--

----=_NextPart_BIG_UUID_1 
Content-Type: application/pdf; name=blah.pdf 
ContentDisposition: attachment;
Content-Transfer-Encoding: base64

JVBERBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLA
HBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLA
HBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLA
HTUzMj5dPj4Kc3RhcnR4cmVmCjQ1ODkyNgolJUVPRgo=


----=_NextPart_BIG_UUID_1--
1个回答

2

看起来没问题,当我试着重现这个问题时它确实能够正常工作(示例在结尾附近)。你需要仔细关注确切的MIME语法,以便在头部和分隔符中产生正确的换行符,如下所述。

电子邮件语法

根据RFC 2046,以下是多部分消息主体结构的一部分摘录。特别注意CRLF。(BNF语法,有些简化)

multipart-body := [preamble CRLF]
                  dash-boundary CRLF
                  body-part *encapsulation
                  close-delimiter
                  [CRLF epilogue]
dash-boundary := "--" boundary
body-part := MIME-part-headers [CRLF *OCTET]
encapsulation := delimiter CRLF body-part
delimiter := CRLF dash-boundary
close-delimiter := delimiter "--"

代码

<?php

$headers  = "From: user@domain.example\r\n";
$headers .= "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: multipart/mixed; boundary=\"--=_NextPart_BIG_UUID_1\"\r\n";

$body  = "----=_NextPart_BIG_UUID_1\r\n";
$body .= "content-type: multipart/alternative; boundary=\"--=_NextAltPart_BIG_UUID_2\"\r\n";
$body .= "\r\n";

$body .= "----=_NextAltPart_BIG_UUID_2\r\n";
$body .= "content-type: text/plain; charset=iso-8859-1\r\n";
$body .= "content-transfer-encoding: quoted-printable\r\n";
$body .= "\r\n";
$body .= "test text content\n";

$body .= "\r\n----=_NextAltPart_BIG_UUID_2";
$body .= "\r\n";
$body .= "content-type: multipart/related; boundary=\"--=_NextAltRelPart_BIG_UUID_3\"\r\n";
$body .= "\r\n";

$body .= "----=_NextAltRelPart_BIG_UUID_3\r\n";
$body .= "content-type: text/html; charset=UTF8\r\n";
$body .= "content-transfer-encoding: quoted-printable\r\n";
$body .= "\r\n";
$body .= "<html><body><h1>BLAH</h1></body></html>\n";

$body .= "\r\n----=_NextAltRelPart_BIG_UUID_3\r\n";
$body .= "content-type: text/plain;\r\n";
$body .= "Content-transfer-encoding: base64\r\n";
$body .= "Content-ID: <whatever_doesnt_matter.txt>\r\n";
$body .= "\r\n";
$body .= "dGVzdCBjb250ZW50\r\n";

$body .= "\r\n----=_NextAltRelPart_BIG_UUID_3--\r\n";

$body .= "\r\n----=_NextAltPart_BIG_UUID_2--\r\n";

$body .= "\r\n----=_NextPart_BIG_UUID_1\r\n";
$body .= "Content-Type: application/pdf; name=blah.pdf\r\n";
$body .= "ContentDisposition: attachment;\r\n";
$body .= "Content-Transfer-Encoding: base64\r\n";
$body .= "\r\n";
$body .= "JVBERBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLA\n";
$body .= "HBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLA\n";
$body .= "HBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLA\n";
$body .= "HTUzMj5dPj4Kc3RhcnR4cmVmCjQ1ODkyNgolJUVPRgo=\r\n";

$body .= "\r\n----=_NextPart_BIG_UUID_1--";

$to = 'user@domain.example';
$subject = 'MIME Test';

return mail ($to, $subject, $body, $headers);
//echo "$headers\n$body\n";

参考资料

注意:本次翻译涉及IT技术,为确保准确性,建议在专业人士的指导下使用。

1
我希望我能给这个点赞一千次。出于某种原因,这是我在互联网上找到的唯一一个编写多部分电子邮件的完整且可工作示例。他们真的应该在那些令人讨厌的RFC规范中放置示例。 不过第17行缺少一个分号(包括空行和<?php行)。 而且我不知道pdf-data末尾的\n\n是否意味着\r\n - doABarrelRoll721
@doABarrelRoll721:干得好!我检查了答案的原始来源,看起来分号在我对字符串内部的行结尾进行最终重新格式化时丢失了。 - Nisse Engström
1
@doABarrelRoll721:重新阅读RFC5322后,发现“CR和LF只能作为CRLF一起出现;在正文中,它们不能单独出现。”因此,两个\n\n的出现是不正确的。谢谢! - Nisse Engström

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接