Адаптивные письма? Пожалуйста!

Давно являюсь мурлыкающим пользователем Яндекс денег, но уже пару месяцев, как испытываю сильный дискомфорт от транзакционных писем-уведомлений. Дело в том, что они не адаптированы под мобильные устройства. В твиттере на мое негодование не ответили, и я решил поставить эту задачу себе на реализацию, как говорится ради фана.

Итак, письмо:

eae529865390a1deb840823f5de07621

Футер нас не особо интересует, ибо там все ок. 

Вот, что мы видим на экране телефона в Android Gmail:

7fe6ab541ad7c51087f6493986dd7f29

Все поехало. Если же мы откроем письмо в Android Mail, то оно будет нормально отображаться, за исключением того, что появится горизонтальная прокрутка. Т.е. письмо не адаптировано под экран смартфона. Этим я и займусь.

Изучаем исходный код письма:

9dc42302564473caab15a69a55aad6d4

В целом все адекватно, вроде делали умные люди, но не тут то было. Используются padding’и для блочных элементов, форматирование текста задается через font, ссылки на оборачиваются span’ами с заданием цвета. В общем наплевали на Outlook, по большому счету. Так и есть, в аутлуке наблюдается ряд «косяков», но они не смертельны. Дальнейший анализ кода показал отсутствие попыток адаптировать письмо под небольшие экраны.

Прежде, чем перейти ближе к делу, заострим внимание на еще одном моменте. Список входящих писем:

a4a610312a2ad1d0043d4e77bc8359c4

Отправитель — Яндекс Деньги. Ок.
Тема — Вы заплатили со счета
Далее текст письма — Платеж успешно выполнен. Это Все хорошо. Но зачем дублировать «Яндекс Деньги»? А появилась эта фраза из-за того, что у логотипа проставлен alt=«Яндекс Деньги». Зачем? Не вижу объективных причин. Можно было бы сослаться на подпись для тех, у кого не загружены картинки. Так почему бы не слать логотип вложением? Тогда он будет показан в любом случае.

Ближе к делу

Смотрим, как можно адаптировать письмо. Для этого, прежде всего, изучим графику. На деле ее оказалось не мало.

6db7454f31717d2ed3774c92dbc07258

1021fd4a713afd7f60e04da869b45b4a

eaba6e881e107c0f980832b8727281dd

46630bbed8ede1a84cd2b27a7f68fc28

96525b348ba84aef4bd5073ab4b08ebf

Звездочки и отстрочку можно было бы просто ужимать до 100% для резиновости адаптивного макета, но тут всплывают два ощутимых минуса:
1. Нижняя часть скрепки является отдельным элементом
2. Звездочки и знаки «=» достаточно мелкие и их ужимание приведет к тому, что они будут плохо читаемы.

Но давайте попробуем ужать то, то есть.

Вот такой результат я получил после пары экспериментов с процентными величинами:

9cdb0a664293d7641af351cbad7e972e

Исходный код для любопытных

<meta charset="utf-8">
<style>
    body {
        margin:0;
    }
    @media only screen and (max-width:442px) {
        .wrapper { width:100% !important; }
        .image { width:100% !important; }
    }
</style>
<table background="https://money.yandex.ru/i/html-letters/bg_texture.png" style="background:url('https://money.yandex.ru/i/html-letters/bg_texture.png');" width="100%" cellpadding="0"cellspacing="0" style="border-collapse:collapse;">
    <tr>
        <td>
            <table class="wrapper" align="center" width="442" cellpadding="0"cellspacing="0" style="border-collapse:collapse;">
                <tr>
                    <td>
                        <table cellpadding="10" cellspacing="0" style="border-collapse:collapse;">
                            <tr>
                                <td width="129" height="74" align="right" valign="bottom">
                                    <a href="https://money.yandex.ru/?_openstat=mail;inform;outpay;logo;" title="Яндекс.Деньги" target="_blank"><img src="https://ci4.googleusercontent.com/proxy/pcc-Zfwujl2NhyxMDskvolE4C3N7sXIcaxOEAVQz2_XS82IeoG65wyAc96pOgIoqrMAZY2jPFa2VcQp54om7GEQQE1Wx=s0-d-e1-ft#https://money.yandex.ru/i/html-letters/logo.png" width="109" height="44" style="border:none; display:block;"></a>
                                </td>
                            </tr>
                        </table>
                    </td>
                </tr>
                <tr>
                    <td colspan="2">
                        <img class="image" src="https://money.yandex.ru/i/html-letters/check_top.png" style="display:block;">
                    </td>
                </tr>
                <tr>
                    <td bgcolor="#ffffff" style="width:83.4%">2121212</td>
                    <td style="width:16.6%" align="right">
                        <img src="https://ci6.googleusercontent.com/proxy/dFUGdcNglNxVtEnimrOQ01vQq4EmO9xg-f8-inzwIGK54WOzI8aV93hILcFvYwSGOWuHq9I2rG1sjA7UGWPs9ecvZRhJukTOSgNmlw=s0-d-e1-ft#https://money.yandex.ru/i/html-letters/check_clips.png" width="74" alt="" style="display:block; width:100%;">
                    </td>
                </tr>
            </table>
        </td>
    </tr>
</table>

Невооруженным взглядом видно, что все очень плохо даже в хроме при размере окна в 320px по ширине. Изображение становится крайне нечетким.

Экспериментирую

Решил попробовать пока забить на скрепку и реализовать ребристый верх при помощи СSS.

290408ac04a6b71520fc7ddcac62bc0b
Это максимум, что у меня получилось.

Исходный код

<meta charset="utf-8">
<style>
    body {
        margin:0;
    }
    @media only screen and (max-width:442px) {
        .wrapper { width:100% !important; }
        .image { width:100% !important; }
    }
</style>
<table background="https://money.yandex.ru/i/html-letters/bg_texture.png" style="background:url('https://money.yandex.ru/i/html-letters/bg_texture.png');" width="100%" cellpadding="0"cellspacing="0" style="border-collapse:collapse;">
    <tr>
        <td>
            <table class="wrapper" align="center" width="442" cellpadding="0"cellspacing="0" style="border-collapse:collapse;">
                <tr>
                    <td>
                        <table cellpadding="10" cellspacing="0" style="border-collapse:collapse;">
                            <tr>
                                <td width="129" height="74" align="right" valign="bottom">
                                    <a href="https://money.yandex.ru/?_openstat=mail;inform;outpay;logo;" title="Яндекс.Деньги" target="_blank"><img src="https://ci4.googleusercontent.com/proxy/pcc-Zfwujl2NhyxMDskvolE4C3N7sXIcaxOEAVQz2_XS82IeoG65wyAc96pOgIoqrMAZY2jPFa2VcQp54om7GEQQE1Wx=s0-d-e1-ft#https://money.yandex.ru/i/html-letters/logo.png" width="109" height="44" style="border:none; display:block;"></a>
                                </td>
                            </tr>
                        </table>
                    </td>
                </tr>
                <tr>
                    <td>
                        <table style="border-top:#ffffff 1px dashed" bgcolor="#d9d9d9" align="center" width="422" height="10" cellpadding="0" cellspacing="0" style="border-collapse:collapse;">
                            <tr>
                                <td bgcolor="#ffffff" style="border-left:#d9d9d9 1px solid; border-right:#d9d9d9 1px solid; border-top:#d9d9d9 1px dashed;">

                                </td>
                            </tr>
                        </table>
                    </td>
                </tr>
            </table>
        </td>
    </tr>
</table>

Вполне неплохо, но не тянет на исходный вариант. Можно реализовать через фоновое изображение, но в этом случае мы потерям аутлук. Хотя кого это беспокоит? Ах-да, меня! Хорошо, реализуем вариант без скрепки и с CSS «огрызком» бумаги.

А вот и результат:

f94fa671e3482a22bbefa9b810a418da

Исходный код

<meta charset="utf-8">
<style>
    body {
        margin:0;
    }
    @media only screen and (max-width:442px) {
        .wrapper { width:100% !important; }
        .check { width:100% !important;}
        .image { width:100% !important; }
        .tile { width:100% !important; float:none !important; width:185px !important; margin:auto; }
    }
</style>
<table background="https://money.yandex.ru/i/html-letters/bg_texture.png" style="background:url('https://money.yandex.ru/i/html-letters/bg_texture.png');" width="100%" cellpadding="0"cellspacing="0" style="border-collapse:collapse;">
    <tr>
        <td>
            <table class="wrapper" align="center" width="442" cellpadding="0"cellspacing="0" style="border-collapse:collapse;">
                <tr>
                    <td>
                        <table cellpadding="20" cellspacing="0" style="border-collapse:collapse;">
                            <tr>
                                <td width="119" height="74" align="right" valign="bottom">
                                    <a href="https://money.yandex.ru/?_openstat=mail;inform;outpay;logo;" title="Яндекс.Деньги" target="_blank"><img src="https://ci4.googleusercontent.com/proxy/pcc-Zfwujl2NhyxMDskvolE4C3N7sXIcaxOEAVQz2_XS82IeoG65wyAc96pOgIoqrMAZY2jPFa2VcQp54om7GEQQE1Wx=s0-d-e1-ft#https://money.yandex.ru/i/html-letters/logo.png" width="109" height="44" style="border:none; display:block;"></a>
                                </td>
                            </tr>
                        </table>
                    </td>
                </tr>
                <tr>
                    <td>
                        <table width="100%" cellpadding="0" cellspacing="0" style="border-collapse:collapse;">
                            <tr>
                                <td width="12" height="10"></td>
                                <td>
                                    <table style="border-top:#ffffff 1px dashed;" bgcolor="#d9d9d9" align="center" width="100%" height="8" cellpadding="0" cellspacing="0" style="border-collapse:collapse;">
                                        <tr>
                                            <td height="10" bgcolor="#ffffff" style="border-left:#d9d9d9 1px solid; border-right:#d9d9d9 1px solid; border-top:#d9d9d9 1px dashed;">
                                                <img src="http://habrastorage.org/files/2ff/ea3/77f/2ffea377fa0e4809bcd3c7636a634cdf.gif" width="10" height="10" alt="" style="display:block;">
                                            </td>
                                        </tr>
                                    </table>
                                </td>
                                <td width="12" height="10"></td>
                            </tr>
                        </table>
                        <table bgcolor="#ffffff" width="100%" cellpadding="0" cellspacing="0" style="border-collapse:collapse;">
                            <tr>
                                <td width="11" style="border:#d9d9d9 1px solid; border-bottom:none; border-right:none;"><img src="http://habrastorage.org/files/2ff/ea3/77f/2ffea377fa0e4809bcd3c7636a634cdf.gif" width="10" height="10" alt="" style="display:block;"></td>
                                <td>
                                    <table bgcolor="#d9d9d9" class="check" align="center" width="100%" cellpadding="5" cellspacing="0" style="border-bottom:#ffffff 1px dashed; border-left:#d9d9d9 1px solid; border-right:#d9d9d9 1px solid;">
                                        <tr>
                                            <td bgcolor="#ffffff" style="border-bottom:#d9d9d9 1px dashed;">
                                                <div align="center" style="line-height:24px;"><span style="font-family:Consolas,monaco,monospace; font-size:14px; color:#666666">*****************************</span></div>
                                                <div align="center" style="line-height:24px;"><span style="font-family:Consolas,monaco,monospace; font-size:14px; color:#666666">Платеж успешно выполнен</span></div>
                                                <div align="center" style="line-height:24px;"><span style="font-family:Consolas,monaco,monospace; font-size:14px; color:#666666">=============================</span></div>

                                                <table width="100%" cellpadding="15" cellspacing="0" style="border-collapse:collapse;">
                                                    <tr>
                                                        <td>
                                                            <div class="tile" style="line-height:18px; float:left; width:50%;"><span style="font-family:Consolas,monaco,monospace; font-size:14px; color:#666666">Назначение платежа</span></div>
                                                            <div class="tile" style="line-height:18px; float:left; width:50%;"><span style="font-family:Consolas,monaco,monospace; font-size:14px; color:#666666"><b>Магазин PYATEROCHKA 38</b></span></div>
                                                            <div style="line-height:0;"><img src="http://habrastorage.org/files/2ff/ea3/77f/2ffea377fa0e4809bcd3c7636a634cdf.gif" style="display:block;" width="10" height="10" alt=""></div>
                                                            <div class="tile" style="line-height:18px; float:left; width:50%;"><span style="font-family:Consolas,monaco,monospace; font-size:14px; color:#666666">Дата и время</span></div>
                                                            <div class="tile" style="line-height:18px; float:left; width:50%;"><span style="font-family:Consolas,monaco,monospace; font-size:14px; color:#666666"><b>16.02.2014 19:27</b></span></div>
                                                            <div style="line-height:0;"><img src="http://habrastorage.org/files/2ff/ea3/77f/2ffea377fa0e4809bcd3c7636a634cdf.gif" style="display:block;" width="10" height="10" alt=""></div>
                                                            <div class="tile" style="line-height:18px; float:left; width:50%;"><span style="font-family:Consolas,monaco,monospace; font-size:14px; color:#666666">Со счета списано</span></div>
                                                            <div class="tile" style="line-height:18px; float:left; width:50%;"><span style="font-family:Consolas,monaco,monospace; font-size:14px; color:#666666"><b>706 руб.</b></span></div>
                                                        </td>
                                                    </tr>
                                                </table>

                                                <div align="center" style="line-height:24px;"><span style="font-family:Consolas,monaco,monospace; font-size:14px; color:#666666">=============================</span></div>
                                                <table width="100%" cellpadding="15" cellspacing="0" style="border-collapse:collapse;">
                                                    <tr>
                                                        <td>
                                                            <div class="tile" style="line-height:18px; float:left; width:50%;"><span style="font-family:Consolas,monaco,monospace; font-size:14px; color:#666666">Доступно</span></div>
                                                            <div class="tile" style="line-height:18px; float:left; width:50%;"><span style="font-family:Consolas,monaco,monospace; font-size:14px; color:#666666"><b>1 345 руб. 77 коп.</b></span></div>
                                                        </td>
                                                    </tr>
                                                </table>
                                                <div align="center" style="line-height:24px;"><span style="font-family:Consolas,monaco,monospace; font-size:14px; color:#666666">*****************************</span></div>
                                                <div align="center" style="line-height:24px;"><span style="font-family:Consolas,monaco,monospace; font-size:14px; color:#666666">Все детали платежа — в вашей <a href="#" target="_blank" style="color:#0b55d9 !important;"><span style="color:#0b55d9">истории</span></a>.</span></div><br>
                                            </td>
                                        </tr>
                                    </table>
                                    <br>
                                </td>
                                <td width="11" style="border:#d9d9d9 1px solid; border-bottom:none; border-left:none;"><img src="http://habrastorage.org/files/2ff/ea3/77f/2ffea377fa0e4809bcd3c7636a634cdf.gif" width="10" height="10" alt="" style="display:block;"></td>
                            </tr>
                        </table>
                    </td>
                </tr>
            </table>
        </td>
    </tr>
</table>

Итоги достигнутого

Минусы:
— Ломается визуальная сетка звездочек и знаков «=»
— Отказ от скрепки
— «Огрызок» бумаги выглядит не так как изначально задумано

Плюсы:
— Убрали 8.5 килобайт ненужной графики(но добавили 50 байт от прозрачной gif распорки)
— Письмо офигенно смотрится на мобильниках
— В целом дизайн практически не изменился

Замечания:
— Поведение мобильного Gmail отличается от результата в других мобильных клиентах в виду того, что Gmail не понимает Media Queries
— Браузерный Outlook проигнорировал все float’ы. Вариант с table align=«left» должен спасти в этом случае.
— Древние версии Outlook не захотели рисовать красивый «огрызок», но и не страшно. Этакий graceful degradation.

P.S.

Как правило игра не стоит таких извращений с версткой. Достаточно лишь немного изменить изначальный дизайн макет для упрощения реализации письма.

Данные наработки могут использоваться кем угодно и в каких угодно целях. Особенно если это поспособствует решению проблемы с письмами-уведомлениями у яндекс-денег.