Это сообщение кажется немного устаревшим, но я знаю эту проблему, потому что я использую более крупное приложение, глубоко укоренившееся на zend FW 1. К сожалению, подсистема Zend_Mail в некоторых местах кажется мне немного неразвитой. Я предполагаю, что библиотеки php, такие как swiftmailer, делают эту работу намного лучше, чем ZF 1.12 и, возможно, даже ZF2. Итак, если переключение обработки почты на swiftmailer не является вариантом и параллельным использованием ZF 1 / ZF 2, который, кажется, дает решения этой проблемы, по некоторым причинам нежелателен: вы застряли в ZF1, как и я.
Я обнаружил, что, как и написал Тим, части вашего составного сообщения 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 (взятого из Zend / Mail / Transport / Abstract.php v.1.12) вы можете создавать сообщения с вашей собственной структурой.
Я дам вам пример опубликованного определения составного сообщения со встроенными изображениями и некоторыми другими двоичными вложениями. Наша требуемая структура вложения мимов:
multipart/mixed
multipart/alternative
text/plain
multipart/related
text/html
image/jpeg
application/pdf
so we do
// 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
Обратите внимание на отсутствие вложения второй смешанной детали, теперь у нас есть только одна деталь, а именно multipart / alternate. В этой ситуации ZF1 Mail сделает это неправильно, потому что он так задуман, что обрабатывает эту конфигурацию только с одним Zend_Mime_Part (альтернативная часть из моего кода) как НЕ-составное письмо и удаляет требуемый составной / альтернативный заголовок из нашего жестко собранный объект 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 ZF1 определяет multipart просто путем подсчета добавленных частей к объекту Zend_Mail, но это неверно в нашей ситуации ручной сборки)
Результат - письмо, которое не то, что вы предполагали.
К счастью, для этой проблемы / ситуации есть простой способ обхода без изменения ZF1.
Просто измените mime заголовка Zend_Mail по умолчанию с multipart / mixed на multipart / alternate (только наш полосатый заголовок) перед отправкой вашей почты.
if($attachcount == 0 && $inlinecount > 0)
$mail->setType('multipart/alternative');
$mail->send();
Теперь окружающая часть почты поменялась со смешанной на альтернативную, что абсолютно правильно для ситуации, когда нет "настоящих" вложений.
Для всех других ситуаций ZF1 изначально составляет почту по мере необходимости, так что с учетом этих примечаний ZF1 v1.12 может обрабатывать сложные конфигурации электронной почты, как и другие хорошие библиотеки электронной почты, и обладает преимуществами интеграции ZF, для которых это полезно.
person
Pete Youlojoke
schedule
03.06.2015