这条消息似乎有点过时了,但我知道这个问题,因为我驱动一个更大的应用程序,深深植根于 zend FW 1。不幸的是,Zend_Mail 子系统在我看来在某些地方有点未开发。
我认为像swiftmailer 这样的 php 库比 ZF 1.12 甚至 ZF2 做得更好。
因此,如果不能将您的邮件处理切换到 swiftmailer 并且并行使用 ZF 1/ ZF 2,这似乎可以解决这个问题,但由于某些原因,您不希望像我一样被困在 ZF1 中。
我发现就像 Tim 发布的那样,您的多部分消息的 mime 部分似乎是错误的顺序和包含关系。我找到了这个订单/包含
multipart/mixed
multipart/alternative
text/plain
multipart/related
text/html
image/jpeg
application/pdf
将执行符合 RFC 的工作并将内联图像与其他附件正确集成。但遗憾的是,您无法使用这种结构构建消息
在 ZF 1 中。
不可能的原因是ZF 1(v1.12)文件中的这部分代码
Zend/Mail/Transport/Abstract.php
protected function _buildBody()
{
if (($text = $this->_mail->getBodyText())
&& ($html = $this->_mail->getBodyHtml()))
{
// Generate unique boundary for multipart/alternative
$mime = new Zend_Mime(null);
$boundaryLine = $mime->boundaryLine($this->EOL);
$boundaryEnd = $mime->mimeEnd($this->EOL);
$text->disposition = false;
$html->disposition = false;
**$body = $boundaryLine
. $text->getHeaders($this->EOL)
. $this->EOL
. $text->getContent($this->EOL)
. $this->EOL
. $boundaryLine
. $html->getHeaders($this->EOL)
. $this->EOL
. $html->getContent($this->EOL)
. $this->EOL
. $boundaryEnd;**
$mp = new Zend_Mime_Part($body);
$mp->type = Zend_Mime::MULTIPART_ALTERNATIVE;
$mp->boundary = $mime->boundary();
$this->_isMultipart = true;
// Ensure first part contains text alternatives
array_unshift($this->_parts, $mp);
// Get headers
$this->_headers = $this->_mail->getHeaders();
return;
}
// If not multipart, then get the body
if (false !== ($body = $this->_mail->getBodyHtml())) {
array_unshift($this->_parts, $body);
} elseif (false !== ($body = $this->_mail->getBodyText())) {
array_unshift($this->_parts, $body);
}
**if (!$body) {
/**
* @see Zend_Mail_Transport_Exception
*/
require_once 'Zend/Mail/Transport/Exception.php';
throw new Zend_Mail_Transport_Exception('No body specified');
}**
这个例程在发送之前组装你的 Zend 多部分邮件消息,并且做了两件没有好处的事情。
1. 是它强制您的正文 html/plan 文本消息采用严格的形式,正如您在 $body 组装的部分中看到的那样。所以没有办法得到
您在此紧身胸衣中的多部分/相关部分
. $boundaryLine
. $html->getHeaders($this->EOL)
. $this->EOL
. $html->getContent($this->EOL)
. $this->EOL
. $boundaryEnd;
因为您在 Zend_Mail 中操作 html 正文部分的唯一方法不允许您使用所需的多部分 mime 而不是空白 html 文本:
setBodyHtml(string $html, string $charset = null, string $encoding = \Zend_Mime::ENCODING_QUOTEDPRINTABLE) :
因此,人们可能会考虑为自己手动做一些事情并从单个部分组装完整的多部分邮件(Zend_Mime_Part 和 Zend_Mime_Message 用于此目的)。
这里我们遇到了第二个问题,或者 ZF 可能会将其视为功能,我不知道。
但是例程中的部分贴出来了
if (!$body) {
/**
* @see Zend_Mail_Transport_Exception
*/
require_once 'Zend/Mail/Transport/Exception.php';
throw new Zend_Mail_Transport_Exception('No body specified');
禁止在未使用 Zend_Mail::setBodyHtml 和 Zend_Mail::setBodyText 调用的情况下进行多部分邮件配置。 (在这种情况下 $body 将是空的)如果它们没有设置,将抛出一个错误,并且所有您手动添加的准确组装消息的 Mime_Parts,使用 Zend_Mail::addPart(Zend_Mime_Part) 添加将被简单地忽略。
要解决这个问题,您必须更改绘图例程的行为以允许多部分消息而不使用 setBodyHtml/setBodyText,如下所示:
if (!$body) {
// this will probably only happen in multipart case
// where we need to assemble manually ..
$this->_isMultipart = true;
// set our manual headers :
$this->_headers = $this->_mail->getHeaders();
return;
/**
* @see Zend_Mail_Transport_Exception
*/
//require_once 'Zend/Mail/Transport/Exception.php';
//throw new Zend_Mail_Transport_Exception('No body specified');
}
在修改 ZF1 代码(取自 v.1.12 Zend/Mail/Transport/Abstract.php)之后,您可以构建
具有您自己的结构的消息。
我会给你一个例子来说明多部分消息的发布定义,内嵌图像和其他一些二进制附件。我们需要的 mime 嵌套结构是
multipart/mixed
multipart/alternative
text/plain
multipart/related
text/html
image/jpeg
application/pdf
所以我们这样做
// create a "multipart/alternative" wrapper
$mailalternative = new Zend_Mime_Message();
// create a "multipart/related" wrapper
$mailrelated = new Zend_Mime_Message();
// text/plain
$mailplain = new Zend_Mime_Part($textmail);
$mailplain->encoding = Zend_Mime::ENCODING_QUOTEDPRINTABLE;
$mailplain->type = "text/plain; charset=UTF-8";
// add it on right place
$mailalternative->addPart($mailplain);
// text/html
$mailhtml = new Zend_Mime_Part($htmlmail);
$mailhtml->encoding = Zend_Mime::ENCODING_QUOTEDPRINTABLE;
$mailhtml->type = "text/html; charset=UTF-8";
// add it to related part
$mailrelated->addPart($mailhtml);
// try to add some inline img attachments
$img_mimes = array('jpg'=>'jpeg','jpeg'=>'jpeg','png'=>'png');
foreach($attachments as $attachment)
if(isset($img_mimes[strtolower($attachment->Typ)]))
{
$suffix = strtolower($attachment->Typ);
$at = new Zend_Mime_Part($attachment->doc_binary);
$at->filename = $attachment->doc_name.'.'.$attachment->Typ;
$at->type = 'image/'.$img_mimes[$suffix].'; name="'.$attachment->doc_name.'.'.$attachment->Typ.'"';
$at->encoding = Zend_Mime::ENCODING_BASE64;
$at->disposition = Zend_Mime::DISPOSITION_INLINE;
// id is important to address your pics in your html
// part later on. If id = XYZ you will write
// <img src="cid:XYZ"> in your html mail part ...
$at->id = $at->filename;
// add them to related part, so they are accessible in html
$mailrelated->addPart($at);
}
$partrelated= new Zend_Mime_Part($mailrelated->generateMessage());
$partrelated->type = Zend_Mime::MULTIPART_RELATED;
$partrelated->boundary = $mailrelated->getMime()->boundary();
$mailalternative->addPart($partrelated);
$partalternative = new Zend_Mime_Part($mailalternative->generateMessage());
$partalternative->type = Zend_Mime::MULTIPART_ALTERNATIVE;
$partalternative->boundary = $mailalternative->getMime()->boundary();
// default mime type of zend multipart mail is multipart/mixed,
// so here dont need to change type and simply set part:
$mail->addPart($partalternative);
// now try to add binary non inline attachments
$img_mimes = array('jpg'=>'jpeg','jpeg'=>'jpeg','png'=>'png');
foreach($attachments as $attachment)
if(!isset($img_mimes[strtolower($attachment->Typ)]))
{
$at = $mail->createAttachment($attachment->doc_binary);
$suffix = strtolower($attachment->Typ);
$at->type = 'application/'.$suffix;
$at->filename = $attachment->doc_name.'.'.$attachment->Typ;
$at->id = $at->filename;
}
现在您可以像往常一样发送手动组装的多部分邮件,其中包含
邮件->发送();
mail->send();
希望这对需要在更高级情况下使用 ZF1 邮件组件的人有所帮助。
需要注意的重要一点:如果您处于某种情况下,您想
仅将内联图像附加到您的邮件中,但不附加其他“真实”附件,
ZF1又给你添麻烦了。。
我说的是这种情况:
multipart/mixed
multipart/alternative
text/plain
multipart/related
text/html
image/jpeg
注意缺少的第二个混合部分附件,我们现在只有一个部分,
即多部分/替代。
在这种情况下,ZF1 Mail 会做错,因为它是如此的概念化,以至于它只使用一个 Zend_Mime_Part(我的代码中的替代部分)作为 NON-multipart 邮件来处理此配置并剥离所需的
来自我们硬组装的 Zend_Mime_Part 对象的 multipart/alternative header。
(看看 Mail/Transport/Abstract.php _send() 例程
$count = count($this->_parts);
$boundary = null;
...
}
if ($count > 1) {
// Multipart message; create new MIME object and boundary
$mime = new Zend_Mime($this->_mail->getMimeBoundary());
$boundary = $mime->boundary();
} elseif ($this->_isMultipart) {
// multipart/alternative -- grab boundary
$boundary = $this->_parts[0]->boundary;
}
在 Zend/Mime/Message.php isMultiPart() 和 generateMessage() 中,
public function isMultiPart()
{
return (count($this->_parts) > 1);
}
你看
问题。 Zend ZF1 仅通过计算添加的部分来确定多部分
到 Zend_Mail 对象,但在我们手动组装的情况下这是错误的)
结果是一封不符合您预期的邮件。
幸运的是,这个问题/情况有一个简单的解决方法,无需更改 ZF1。
在发送之前,只需将默认 Zend_Mail 标头 mime 从 multipart/mixed 更改为 multipart/alternative(只是我们删除的部分标头)
你的邮件
if($attachcount == 0 && $inlinecount > 0)
$mail->setType('multipart/alternative');
$mail->send();
现在邮件的周围部分已经从混合变为替代,对于没有“真实”附件的情况来说这是绝对正确的。
对于所有其他情况,ZF1 本身会根据需要撰写邮件,因此通过处理此注释,ZF1 v1.12 可以像其他优秀的电子邮件库一样处理复杂的电子邮件配置,并具有 ZF 集成的优势受益。