Ruby on Rails

индекс
81,97

Как быть с HTML-письмами?

Недавно столкнулся с задачей по верстке HTML-писем. Как известно, многие почтовые клиенты, в том числе и Gmail игнорируют css-классы и содержимое тега style, не говоря уже о подключении внешних CSS-файлов. Поэтому обычной практикой при верстке HTML-писем является использование inline-стилей. Если делать это самостоятельно, то шаблон письма очень быстро превращается в кашу, поддерживать и расширять которую очень сложно. В связи с чем rails-разработчики используют различные плагины, которые позволяют «встроить» css-класс в аттрибут style.

Пишем обычный html в теле письма:

<div class="test">hello world</div>


и говорим плагину, сделай inline-стили, используя следующую css-ку:

div.test { font-size: 12px; color: red; }


после чего на выходе получаем такой код:

<div class="test" style="font-size: 12px; color: red;">hello world</div>


Таким образом, с одной стороны мы имеем читаемые, расширяемые и легко поддерживаемые шаблоны html-писем, а с другой — наши шаблоны нормально перевариваются различными почтовыми клиентами.
После того как я узнал о прекрасном плагине awesome_email мне казалось что никаких проблем возникнуть не может, ведь принцип использования прост как валенок: указывает из каких css-ок брать стили и говорим — «заинлайнь их». Но не тут то было, письма стали приходить не в том виде, в котором должны были. Чтобы понять природу ошибки рассмотрим принцип работы awesome_email (который, как оказалось, совсем не awesome). Сначала с помощью плагина css_parser разибирается на составляющие указанная css-ка, потом с помощью nokogiri распарсивается html-документ, ну и наконец, в цикле по селектору каждого css-правила получаются html-элементы и для каждого из них в конец style дописывается содержимое правила. Вот к чему это может привести:

CSS:
div.test:first-child {color: red;}
div.test {color: green;}


HTML:
<div class="test">hello world</div>


OUTPUT:
<div class="test" style="color: red; color: green;">hello world</div>


Мало того, что css-свойство color дублируется, так оно еще и применяется неправильно, потому что в цикле по CSS-правилами не учитывается их значимость, а просто сначала добавляется содержимое первого css-правила, а потом второго, в связи с чем цвет текста зеленый, хотя должен быть красным. Данной проблемы можно было бы избежать следующим способом: проходить в цикле не по css-правилам, а по html-элементам, и для каждого, каким-то образом получать все связанные с ним css-правила (как при просмотре кода через firebug), но это только гипотеза и как лучше реализовать такое поведение я не знаю. Поэтому главный вопрос таков: как лучше всего встраивать стили html-письма в rails приложении? Какие плагины использовать, чтобы с одной стороны, шаблон письма оставался понятным и расширяемым, а с другой — почтовые клиенты были довольны и отображали содержимое как задумано?

UPD. Задача решена. Вот код: github.com/goganchic/awesome_email а вот сопутствующая статья: rails.vsevteme.ru/items/show?id=15682
+17
6 августа 2010, 01:38
24

комментарии (38)

+2
Octane #
Я бы решал эту проблему при помощи UserJS, чтобы вообще не писать сложные парсеры, в браузерах это уже все есть, достаточно после загрузки страницы пройтись по всем элемента и дописать в style.cssText стили, полученные при помощи getComputedStyle.
0
Octane #
Хотя серверное решение конечно же может понадобиться…
–1
adontz #
Javascript в почтовом сообщении штука сомнительная. Например, в Thunderbird 3 он выключен.
+2
Octane #
Javascript в самом сообщении и не нужен, здесь о преобразовании перед отправкой речь идет.
0
Goganchic #
ммм, интересная идея, только письма-то заранее сделанные, типа активации пользователя, прогонять их через браузер совсем не хочется, не удобно это
0
Goganchic #
вот если бы можно было поставить на сервер браузер какой-нибудь, типа firefox-а и заставить его что-то сотворить с html-кой + css в фоне, чтобы это было не на стороне пользователя — вот это было бы круто
–3
tenshi #
оно возвращает значения в пикселях. по твоему у всех монитор такой же как у тебя?
+4
ikido #
Css parser отлично работает, я например просто составляю css-ки с расчетом на то что они будут использоваться в письмах, т.е. не использую сложные селекторы и наследование, получаются классы вроде strong_text и strong_red_text, различающиеся только цветом.
0
Goganchic #
тоже вариант, но отказываться от всех перимуществ css из-за почты — я не могу пойти на такое
+1
ikido #
Ну тут уже зависит от ваших писем и задач конечно. Но с другой стороны — это всего лишь письмо, я на своей практике ни разу не видел письма где нельзя было бы обойтись без вложенности стилей и всяких таких примочек.

Ну и кстати вы можете генерировать css) Sass вам в помощь.
0
Goganchic #
если бы это было просто письмо — то да, можно было бы обойтись без вложенности стилей и всяких примочек, но хочется-то использовать уже существующий код, который используется на основном сайте, например, на сайте есть красивая панелька, она уже сверстана и оттестирована, находится в отдельном partial-е, хочется в письме сделать:

render :partial => 'shared/panel'

и не заморачиваться больше. Да, я понимаю, что по большому счету для лучшей поддержки почтовыми клиентами было бы круто переверстать все это дело таблицами, убрать все сложные, неподдерживаемые css-правила и т.п. но хочется-то, хотя бы на первое время, сделать быстрое решение, чтобы показать его начальству, а потом уже в фоне по мере сил и возможностей перевестать по-правильному.
0
Aux #
Неправильное решение. Сайт — это сайт. Письмо — это письмо. По-хорошему, вы не должны использовать в письме такие элементы сайта, как красивая панелька. Вы хоть в одной рассылке такой бред видели? Подпишитесь на рассылку Apple и посмотрите как надо правильно офорлять рассылки.
0
tenshi #
это от каких? неужели так сложно более общие селекторы писать вначале?
+5
vadimbelyaev #
Самое главное правило HTML-писем: обязательно включать в сообщение и plain text-версию.
0
Goganchic #
вы безусловно правы! но что делать с html-версией? :)
+3
aps #
Фтопку
0
SabMakc #
Если в письме есть аттачмент картинки, то в HTML-ке ее можно отобразить. Возможно, и со стилями такой трюк пройдет.
Техника такая:

где 25bc9b0e72ffee30f74314732989afd7 — Content-Id картинки в письме. На сколько помню, Content-Id может быть любым, я ставил имя файла.
0
SabMakc #
Немного неправильно отправил.
Техника такая:
<img src="cid:25bc9b0e72ffee30f74314732989afd7">
где 25bc9b0e72ffee30f74314732989afd7 — Content-Id картинки в письме. На сколько помню, Content-Id может быть любым, я ставил имя файла.
0
tzlom #
не все почтовики поддерживают вставленный CSS документ
хотя конечно не поддерживают его только браузерные типа gmail, по очевидным причинам
+2
lolmaus #
По-моему, лежащее на поверхности решение — отказаться от семантики и использовать CSS-классы вроде «red» «100-percent-wide».

Мерзко, но в случае с почтой может быть оправдано.
0
ikido #
или не отказываться и генерить страшный css.
В любом случае придется обходить ограничения email-клиентов — от них пока никуда не деться
0
k12th #
Такая же проблема стоит перед верстальщиками виджетов для вставки в блоги.
Например, ЖЖ еще и некоторые инлайновые объявления режет (position: relative и absolute).

Мне кажется, можно написать простенькое расширение для внутреннего пользования (под FF или Chrome), по совету тов. Octane, и генерить с его помощью шаблоны. Не так уж часто эти шаблоны меняются, имхо.
0
Goganchic #
да, наверное так и придется делать, спасибо за совет!
НЛО прилетело и опубликовало эту надпись здесь
0
qbique #
аутлук ваще жжёт. у него свой собсвенный движок рендеринга ХТМЛ, который очень похож на то, как рендерит разметку Word. так что для писем основной принцип — чем проще, тем лучше. иначе есть все шансы взорвать себе мозг, пытаясь понять почему в аутлуке письмо выглядит так странно
НЛО прилетело и опубликовало эту надпись здесь
0
kyrie #
Мы в свое время отказались от html в письмах, из-за неадекватного восприятия — половина пользователей отправляет письмо с html в корзину не читая даже заголовок. Необходимый контент генерировался на сервере, а в письмо была вставлена личная ссылка.

Это далеко не универсальный способ, во-первых лишний клик, во-вторых безопасность.
0
medin #
Мы тоже рассылаем html письма, но их читает далеко не 50%.

Все нормальные импортные магазины присылают html письма.

Все чинно, красиво и никакого спама и люди читают. Так что не стоит наезжать на красивые письма.
0
xaxaTyH #
apple.com рассылает офигенно красиво сверстанные письма.
Я уверен, что они немного больше вас.
0
magicstream #
пора бы уже и email стандартам начать развиваться.
0
g0dlike #
www.asciiribbon.org/
Присоединяйтесь
0
aps #
хрестоматийное от Зельдмана:
«E-mail is not a platform for design»
www.zeldman.com/2007/06/08/e-mail-is-not-a-platform-for-design/
Русский перевод:
www.newsland.ru/News/Detail/id/82184/
+1
akzhan #
По-моему, поскольку проблема описана, проще всего форкнуться и решить её.

В методе
def render_inline(css_doc, html_doc)

надо просто получить список всех селекторов и потом просто отсортировать по увеличению важности.

Цитирую Википедию:

Приоритеты рассчитываются таким образом (от большего к меньшему):
свойство задано при помощи !important?
стиль прописан напрямую в теге?
количество идентификаторов (#id) в селекторе (чем больше, тем больше приоритет);
количество классов (.class) и псевдоклассов (:pseudoclass) в селекторе;
количество имён тегов в селекторе;
Кроме того, имеет значение относительный порядок расположения свойств — свойство, указанное позже, имеет приоритет.

В общем, вполне реализуемо, за небольшое время. Если бы мне было нужно, я бы реализовал.
0
Goganchic #
надо попробовать, но что-то мне подсказывает что тут не все так просто как кажется
+1
Goganchic #
в общем, я реализовал задуманное
вот сопутствующая статья: rails.vsevteme.ru/items/show?id=15682
а вот код: github.com/goganchic/awesome_email
+1
akzhan #
Молодцом!

Теперь можно отправить pull request и все мы будем благодарны тебе при случае!
0
Josijon #
Microsoft часто делает рассылку и все отображается очень корректно, картинки к картинкам, тексты к текстам, все, что не хочешь — не открываешь. Просто заверстанная страничка — очень удобно мне кажется…
0
WaveMeUp #
Отлично! RC очень порадовал. Правда сначала было немного непривычно, т.к. изменились некоторые обыденные команды, а так очень нравится. Ждём полного Релиза"

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.