Включение CSS в электронное письмо, отправленное из задачи в symfony

Я пытаюсь отправить электронное письмо в формате HTML из задачи symfony (1.4.6), я не хочу отправлять весь визуализированный вывод HTML из определенного модуля/действия, поэтому я визуализирую частично. Все в порядке, проблема в том, что партиал содержит ссылки на CSS.

Есть ли хороший «симфонический» способ включения файла CSS в электронное письмо в формате HTML из задачи symfony, когда все, что я делаю, это рендеринг определенного фрагмента? Или это единственное решение — создать заголовок/тело HTML вручную внутри задачи, используя file_get_contents(cssFile) для захвата файла CSS, а затем объединяя отрендеренный фрагмент?

Любые мысли будут оценены.


person chattsm    schedule 06.08.2010    source источник
comment
Есть и другая информация о CSS в электронных письмах, которую вы можете посмотреть: campaignmonitor.com/css   -  person Navarr    schedule 06.08.2010
comment
Хорошо, это полезно, спасибо. Я предполагаю, что одно из решений состоит в том, чтобы добавить все стили непосредственно в теги HTML, но я надеялся избежать этого... CSS, который я хочу включить, совсем не сложен.   -  person chattsm    schedule 06.08.2010


Ответы (1)


Я столкнулся с той же проблемой в своем проекте. Вот как я это исправил:

  1. Чтобы сохранить CSS отдельно, но встроить его перед отправкой электронной почты, мы используем Emogrifier. Загрузите исходный код и поместите его в %sf_lib_dir%/vendor/emogrifier.

  2. Создайте класс myMailer, расширяющий sfMailer. Мой ниже. Есть несколько отдельных функций, но ключевой функцией является composeAndSendPartial, которая принимает частичное имя (в виде строки), вставляет весь встроенный CSS и отправляет его. Я попытался удалить весь код, относящийся к моему проекту, но, возможно, я оставил часть кода. Сообщите мне, если это не сработает для вас или у вас возникнут вопросы.

  3. В factory.yml установите mailer: на myMailer

myMailer.class.php:

<?php
class myMailer extends sfMailer
{
  /**
   * Creates a new message with 2 bodies:
   * * 1 with $body and MIME type text/html.
   * * 1 with $body and tags stripped with MIME type text/plain. Stipped <br/>, </p>, and </div> tags and replaced with \n
   *
   * @param string|array $from    The from address
   * @param string|array $to      The recipient(s)
   * @param string       $subject The subject
   * @param string       $body    The body
   *
   * @return Swift_Message A Swift_Message instance
   */
  public function composeAndSendHtml($from, $to, $subject, $body)
  {
    return $this->send($this->composeHtml($from, $to, $subject, $body));
  }


  /**
   * Sends a message using composeHtml.
   *
   * @param string|array $from    The from address
   * @param string|array $to      The recipient(s)
   * @param string       $subject The subject
   * @param string       $body    The body
   *
   * @return int The number of sent emails
   */
  public function composeHtml($from = null, $to = null, $subject = null, $body = null)
  {
    return Swift_Message::newInstance()
      ->setFrom($from)
      ->setTo($to)
      ->setSubject($subject)
      ->addPart($this->createPlainTextBody($body), 'text/plain')
      ->addPart($body, 'text/html');
  }


  /**
   * Attempts to create a plaintext message with all html tags stripped out and new lines inserted as necessary
   * @param $body
   * @return $body
   */
  public function createPlainTextBody($body)
  {
    $body = preg_replace('/\<br\s*\/?\>/i', "\n", $body); //replace all <br/s> with new lines
    $body = preg_replace('/\<\/p\s*\>/i', "</p>\n\n", $body); //append 2 newlines to the end of each </p>
    $body = preg_replace('/\<\/div\s*\>/i', "</div>\n\n", $body); //append 2 newlines to the end of each </div>
    $body = strip_tags($body); //strip all tags from the body
    return $body;
  }

  /**
   * Composes and sends an email with a body from rendering $partial with $parameters
   * @param string $from
   * @param string $to
   * @param string $subject
   * @param string $partial the partial as a string. Feel free to change the default module name below
   * @param array $parameters Parameters for the partial
   * @param array $globalStylesheets The stylesheets that are included globally (usually global.css, maybe others)
   */
  public function composeAndSendPartial($from, $to, $subject, $partial, $parameters = array(), $globalStylesheets = array())
  {
    require_once(sfConfig::get('sf_lib_dir') . '/vendor/emogrifier/emogrifier.php');

    $context = sfContext::getInstance();
    $response = $context->getResponse();
    $originalStylesheets = $response->getStylesheets();

    if (false !== $sep = strpos($partial, '/'))
    {
      $moduleName   = substr($partial, 0, $sep);
      $templateName = '_' . substr($partial, $sep + 1);
    }
    else
    {
      $moduleName = 'email';
      $templateName = '_' . $partial;
    }

    sfConfig::set('sf_is_email', true);
    $view = new sfPHPView($context, $moduleName, $templateName, ''); #not sure what 4th parameter does
    $view->getAttributeHolder()->add($parameters);
    $view->setDecorator(true);
    $view->setDecoratorTemplate('email.php');
    $html = $view->render();
    sfConfig::set('sf_is_email', false);

    $emailStylesheets = array_keys(array_diff_key($response->getStylesheets(), $originalStylesheets));

    $css = '';
    foreach($globalStylesheets as $globalStylesheet)
    {
      $css .= file_get_contents(sfConfig::get('sf_web_dir') . '/css/' . $globalStylesheet . '.css');
    }
    foreach ($emailStylesheets as $stylesheet)
    {
      $css .= file_get_contents(sfConfig::get('sf_web_dir') . '/css/' . $stylesheet . '.css');
      $response->removeStylesheet($stylesheet);
    }

    $emog = new Emogrifier($html, $css);
    $body = $emog->emogrify();

    $this->composeAndSendHtml($from, $to, $subject, $body);
  }
}   
person Alex Grin    schedule 06.09.2010