このメッセージは少し古くなっているようですが、私は zend FW 1 に深く根差したより大きなアプリケーションを動かしているので、この問題を知っています。私は、 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 マルチパート メール メッセージを送信する直前に組み立て、2 つのことを行います。1. $body が組み立てられている部分でわかるように、body html/plan テキスト メッセージを厳密な形式で強制することです。したがって、このコルセットでマルチパート/関連セクションを取得する方法はありません
. $boundaryLine
. $html->getHeaders($this->EOL)
. $this->EOL
. $html->getContent($this->EOL)
. $this->EOL
. $boundaryEnd;
Zend_Mail で HTML 本文部分を操作する唯一の方法では、空白の HTML テキストの代わりに必要なマルチパート MIME を使用できないためです。
setBodyHtml(string $html, string $charset = null, string $encoding = \Zend_Mime::ENCODING_QUOTEDPRINTABLE) :
そのため、自分で手動で作業を行って、単一の部分から完全なマルチパート メールを組み立てることを考える人もいるかもしれません (Zend_Mime_Part と Zend_Mime_Message を使用します)。
ここで 2 番目の問題が発生します。または、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 は空になります) それらが設定されていない場合、エラーがスローされ、Zend_Mail::addPart(Zend_Mime_Part) で追加された、正確に組み立てられたメッセージの手動で追加された Mime_Parts はすべて無視されます。
これを回避するには、プロットされたルーチンの動作を変更して、次のように 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(); を使用して、手動で組み立てたマルチパート メールを通常どおりに送信できます。
mail->send();
これが、より高度な状況で ZF1 のメール コンポーネントを使用する必要がある人々に役立つことを願っています。
注意すべき重要な点: インライン画像のみをメールに添付し、他の「真の」添付ファイルを添付したくない状況にある場合、ZF1 は再び問題を引き起こします..私はこの状況について話している:
multipart/mixed
multipart/alternative
text/plain
multipart/related
text/html
image/jpeg
欠落している 2 番目の混合パートの添付ファイルに注意してください。現在、1 つのパート、つまり multipart/alternative しかありません。この状況では、ZF1 メールは間違った動作をします。なぜなら、ZF1 メールは非常に概念化されているため、Zend_Mime_Part (私のコードの代替部分) を 1 つだけ使用してこの構成を非マルチパート メールとして処理し、必要なマルチパート/代替ヘッダーを削除するからです。ハードアセンブルされた Zend_Mime_Part オブジェクト。(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 ZF は、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 統合のメリットを享受できます。