За последние несколько месяцев в различных группах Discourse поступило множество запросов на улучшение обработки входящей электронной почты. Если выразить эти запросы в виде пользовательских историй, их можно разделить на три основные категории:
- «Я хочу иметь возможность использовать те же функции HTML при ответе по электронной почте, что и при публикации на сайте».
- «Я хочу иметь возможность просматривать и искать сообщения из нашей рассылки».
- «Я хочу, чтобы контент, созданный по электронной почте — как через ответ по почте, так и при пакетном импорте — всегда был красиво оформлен и корректно обработан».
Ниже я приведу ссылки на реальные примеры таких запросов, но сейчас важно понять главное: все три, казалось бы, «разных» запроса на самом деле направлены на достижение одной и той же цели — более точной обработки входящей электронной почты.
Несколько месяцев назад я написал @sam с предложением подключить Discourse к коммерческому API для обработки электронной почты, которое предлагает наша компания. Сэм предложил создать здесь тематическое обсуждение, чтобы объяснить преимущества интеграции с нашим API по сравнению с существующим решением Discourse для обработки входящей почты, а также то, как наш API может быть интегрирован в виде плагина.
Я подробно рассмотрю обе эти темы, начав с текущего состояния решения Discourse для обработки электронной почты. И для тех, кто последние несколько лет не задумывался о проблемах обработки почты, я также предоставлю некоторый контекст, описывающий суть проблемы.
Этот пост довольно длинный, но вы можете пропустить ненужные части. Вот что будет рассмотрено:
- Текущее состояние обработки электронной почты в Discourse
- Преимущества более качественной обработки электронной почты
- Персоны ключевых заинтересованных сторон
- API обработки электронной почты FWD:Everyone
A. Удаление подписей и предыдущих ответов
B. Нормализация HTML-разметки
C. Поддержка языков
D. Стилизация с помощью CSS - Предлагаемая интеграция
- Тестирование API
Текущее состояние обработки электронной почты в Discourse
В Discourse уже есть функция «ответ по электронной почте», которая преобразует ответы пользователей в новые сообщения форума в рамках темы. Эта функция работает следующим образом:
- Пользователь получает уведомление по электронной почте с новым сообщением в теме форума, за которой он следит.
- Пользователь отвечает на это письмо.
- Этот ответ по электронной почте преобразуется в новое сообщение в соответствующей теме форума.
Концептуально это бесценная функция; это предпочтительный рабочий процесс для многих людей и обязательное требование для многих сообществ, основанных на рассылках, которые рассматривают возможность миграции на Discourse.
Однако проблема заключается в том, что при преобразовании этих ответов по электронной почте в сообщения форума они часто отображаются с отсутствующим или некорректным форматированием, а иногда и с потерей текста. Это крайне проблематично, причины чего я объясню ниже.
К распространенным проблемам относятся:
- Неправильное отображение маркированных списков
- Отсутствие разрывов строк между текстом
- Избыточные разрывы строк между текстом
- Полное удаление текста, написанного пользователем
И когда я говорю, что эти проблемы распространены, я имею в виду не то, что они иногда возникают при отправке писем на иностранных языках с использованием малоизвестных почтовых клиентов. Я имею в виду, что они часто возникают при отправке базовых ответов по электронной почте из Gmail и Outlook на английском языке.
Вот два реальных примера жалоб пользователей на эти проблемы, оба из рассылки [Python-Dev]:
https://www.prettyfwd.com/t/Wco-c1ZCR7mUwiww0j6s9w/#message-5
https://www.prettyfwd.com/t/Wco-c1ZCR7mUwiww0j6s9w/#message-36
(Prettyfwd использует API обработки электронной почты FWD:Everyone.)
Хотя я не пробовал импортировать контент из существующих рассылки в Discourse, исходя из своего опыта могу сказать, что если процент ошибок при ответе по электронной почте составляет X, то процент ошибок при отображении целых цепочек писем будет как минимум на порядок выше. Это связано с повышенной сложностью удаления подписей и предыдущих ответов, учета встроенных ответов, работы с глубоко вложенной разметкой и т. д.
В качестве реального примера можно привести ретроспективу миграции с Mailman на Discourse, написанную Таней Латтнер (президентом фонда LLVM), в разделе технических проблем упоминаются эти проблемы:
Я уточнил, и оказалось, что именно их возмущает высокий процент писем, в которых отсутствует контент из-за преждевременного обрезания. Поскольку существующие обсуждения и документация за последние 19 лет архива рассылки имеют неоценимую ценность, они считают, что не смогут отказаться от использования Mailman, пока эта проблема не будет полностью решена.
Итак, как мы можем определить, достаточно ли хорош текущий уровень обработки электронной почты в Discourse? Я предлагаю следующий трехчастный тест:
- Пользователи должны полностью доверять тому, что при использовании функции «ответ по электронной почте» их контент будет точно обработан и будет выглядеть так же хорошо, как если бы они опубликовали его через веб-интерфейс.
- Администраторы форума должны доверять тому, что разрешение функции «ответ по электронной почте» не создаст дополнительной работы и жалоб.
- Сотрудники Discourse должны достаточно доверять этой функции, чтобы активно продвигать её как первоклассный способ участия.
Если мы не можем с полной уверенностью сказать, что выполняются все эти условия, то даже при наличии функции «ответ по электронной почте» подавляющее большинство потенциальных преимуществ никогда не будет реализовано.
Именно это и происходит в настоящее время.
То есть я бы охарактеризовал существующий код обработки электронной почты как решение по правилу 80/20, но в контексте, где такое решение не имеет смысла; проблема в том, что даже если, например, 80% писем обрабатываются правильно, вы, скорее всего, получите менее 10% потенциальных преимуществ.
Таким образом, хотя функция «ответ по электронной почте» (и пакетный импорт писем) уже существует, пользователи в конечном итоге не получают ожидаемого опыта, для модераторов и сотрудников создается дополнительная работа, сообщества теряют ценный контент и рост пользователей и т. д.
Преимущества более качественной обработки электронной почты
Социальное программное обеспечение успешно только в той мере, в какой оно удовлетворяет человеческие потребности.
Причины, по которым люди публикуют сообщения на веб-форумах, включают желание поделиться знаниями с другими, повлиять на их мнение, быть воспринятым как умный человек, как эксперт в предметной области, как вносящий ценный вклад в реальную жизнь и т. д.
Когда речь идет о текстовой коммуникации, вероятность достижения этих результатов зависит не только от того, что сказано, но и от типографики, с помощью которой это сказано.
Именно поэтому существуют целые книги о пробелах в произведениях Шекспира. Это отчасти причина, по которой The NY Times воспринимается более серьезно, чем The NY Post. И это во многом причина, по которой Facebook победил MySpace.[1]
Когда текст, написанный пользователем, оказывается плохо отформатированным не по его вине, человеческие потребности, побуждающие людей использовать социальное программное обеспечение, больше не удовлетворяются. На самом деле происходит обратное: пользователи выглядят глупо.
Даже те, кто не использует функцию «ответ по электронной почте», теряют авторитет и уважение, если другие сообщения в теме (и на всем форуме) выглядят как свалка.
Персоны ключевых заинтересованных сторон
Хотя все выигрывают, когда сообщения последовательно отображаются с эстетически приятной типографикой, следующие типы пользователей могут особенно выиграть от улучшения обработки входящей электронной почты:
- Люди, которые в настоящее время являются участниками рассылки, таких как [Python-Dev] и [Django-Dev], которые полностью понимают преимущества Discourse и рады видеть, что их сообщества переходят на Discourse, но только если они смогут продолжать участвовать таким образом, который неотличим от GNU Mailman, Google Groups и т. д. Вот реальный пример такого запроса: https://www.prettyfwd.com/t/Wco-c1ZCR7mUwiww0j6s9w/#message-89
- Участники почтовых сообществ, которые в целом были бы рады мигрировать на Discourse, но были бы гораздо более энтузиастичны, если бы их десятилетия существующего контента можно было легко искать в рамках одной платформы.
- Случайные пользователи, которые периодически проверяют форумы. Например, на Growing Fruit я подписан по электронной почте на все темы о выращивании североамериканской папайи (pawpaw). Летом и осенью я посещаю этот форум несколько раз в день, чтобы читать постоянный поток новых сообщений в этих темах, но вне этих месяцев меня удерживают в основном уведомления по электронной почте по этим темам.
- Люди, которые используют веб-интерфейс только периодически. Часто предполагается, что если люди не регулярно используют веб, то это связано с цифровым разрывом, но часто это не так. Существует множество людей, которые являются одновременно высокоинтеллектуальными и технически подкованными, но изолированы от необходимости регулярно использовать веб-интерфейс из-за того, что находятся на вершине своей профессии. Реальным примером здесь может быть Дональд Кнут, который не регулярно использует веб-интерфейс, несмотря на то, что является одним из ведущих современных компьютерных ученых. В каждой сфере есть такие люди, и привлечение их к обмену знаниями имеет неоценимое значение. По моему опыту, такие люди вряд ли станут регулярными участниками любого форума, но если кто-то скажет им, что есть тема, обсуждение которой их заинтересует, они часто подпишутся по электронной почте и будут участвовать в обсуждении этих конкретных тем.
Общая картина такова: улучшение обработки входящей электронной почты должно не только повысить вовлеченность людей, которые уже являются активными регулярными участниками Discourse, но и разблокировать множество сообществ, которые хотели бы мигрировать на платформу, а также привлечь высокоценный контент от людей, которые в противном случае не участвовали бы.
API обработки электронной почты FWD:Everyone
API обработки электронной почты FWD:Everyone выполняет две задачи:
- Точно удаляет подписи и предыдущие ответы из каждого электронного письма, сохраняя при этом возможность встроенных ответов на цитируемый текст.
- Преобразует чрезвычайно сложную HTML-разметку, генерируемую почтовыми клиентами, в нормализованную разметку из ~12 тегов HTML, которые обычно разрешены на сайтах с пользовательским контентом — при этом максимально сохраняя намерения автора.
Я объясню обе эти задачи более подробно, но сначала вот видео, которое я сделал, объясняющее проблему на примере реальных цепочек писем: https://www.youtube.com/watch?v=nPb3NQlz6V4
Удаление подписей и предыдущих ответов
API обработки электронной почты FWD:Everyone работает как с текстовыми, так и с HTML-письмами с одинаковой точностью. API предпочтительно использует HTML-часть сообщения, если она доступна, потому что:
- Функции форматирования HTML (например, жирный шрифт, курсив, цитаты, фрагменты кода и т. д.), которые выбирает автор, являются неотъемлемой частью сообщения автора, так же важны, как и сам текст.
- При конвертации HTML-версии сообщения в текстовую версию почтовые клиенты часто делают это неправильно. Например, почтовые клиенты часто даже не пытаются отобразить функции HTML, такие как маркированные списки, в текстовом виде, а часто текст внутри элементов форматирования HTML полностью отсутствует.
Конечно, некоторые пользователи предпочитают отправлять текстовые письма; поэтому текстовые письма без HTML должны обрабатываться с одинаковой точностью при удалении подписей и предыдущих ответов.
API обработки электронной почты FWD:Everyone делает это, включая правильное обработка встроенных ответов как в текстовых, так и в HTML-письмах.
Что касается точности, существуют два типа ошибок, которые могут возникнуть в любой библиотеке обработки электронной почты при удалении подписей и предыдущих ответов:
- Ложноположительные результаты — когда текст, который должен быть включен в сообщение, ошибочно исключается.
- Ложноотрицательные результаты — когда текст, который не должен быть включен в сообщение, ошибочно включается.
Трудно дать точную статистику точности, потому что разные сообщества Discourse (с маленькой буквы) используют электронную почту по-разному. Но по сравнению с текущим решением Discourse для обработки почты реалистичные ожидания могут быть следующими:
- В 100 раз меньше ложноположительных результатов при удалении подписей и предыдущих ответов
- В 10 раз меньше ложноотрицательных результатов при удалении предыдущих ответов
- В 1–10 раз меньше ложноотрицательных результатов при удалении подписей — вероятно, лучше, но не на целый порядок.
Для контекста: ложноположительные результаты обычно гораздо хуже, чем ложноотрицательные, поскольку они искажают то, что написал человек. Но ложноотрицательные результаты также очень плохи, так как они заставляют автора (и всех остальных на форуме) выглядеть непрофессионально в лучшем случае и откровенно глупо в худшем.
Подход, который использует FWD:Everyone, заключается в отказе от любых трюков для удаления подписей, которые могут привести к ложноположительным результатам; предполагаемое увеличение ложноотрицательных результатов в этом случае в значительной степени компенсируется тем, что было проделано огромной работы по легитимной работе алгоритма без необходимости идти на компромиссы.
Главная причина, по которой API обработки электронной почты FWD:Everyone будет в целом намного точнее, чем текущее решение Discourse, заключается в том, что наш API был разработан для обработки целых цепочек писем, что является гораздо более сложной задачей, чем обработка разовых ответов по электронной почте. В результате наш продукт является сильно переусложненным, по крайней мере, по сравнению с потребностями Discourse и существующими аналогами.
Нормализация HTML-разметки
Для того чтобы ответы, отправленные по электронной почте (и импортированные цепочки писем), выглядели так же, как любой другой пользовательский контент, они должны в конечном итоге отображаться с использованием того же подмножества HTML, который разрешен при ответах через веб-сайт.
Это удивительно сложно.
Письма, составленные в почтовых клиентах, таких как Gmail и Outlook, кодируются с использованием комбинации из ~50 тегов HTML, ~25 атрибутов HTML и ~175 стилей CSS. Кроме того, эта разметка часто сильно запутана; вы могли бы ожидать, что абзац текста будет выглядеть примерно так:
<p>Какой-то текст!</p>
Но вместо этого даже простые абзацы часто кодируются с использованием глубоко вложенных и совершенно бессмысленных комбинаций div, span, таблиц, списков и т. д. Это основной источник сложности как при удалении предыдущих ответов, так и при нормализации разметки.
Тем не менее, после обработки каждое сообщение отображается только с использованием следующей разметки:
Разрешенные блочные элементы: <p>, <ul>, <ol>, <li>, <blockquote>, <pre>
Разрешенные строчные элементы: <code>, <a>, <b>, <i>, <u>, <s>, <span>
Примечания:
- Единственные разрешенные атрибуты (кроме тегов
<a>) — это'style'и'dir'. - Единственный разрешенный строчный стиль —
'font-weight'. - Теги
<a>также могут иметь атрибуты'href','rel','title'и'target'. - Элементы
<span>используются только в ограниченных случаях для обеспечения правильного каскадного применения жирности шрифта. Поэтому они всегда используются со строчным'font-weight'. - В будущем тег
<img>также будет использоваться для отображения встроенных изображений.
Отображение сообщений в этом ограниченном подмножестве HTML позволяет любому сообщению, отправленному по электронной почте, легко отображаться с использованием той же типографики, что и сообщения, отправленные через веб-интерфейс.
Всё это делается с максимальным сохранением намерений автора, а также с обеспечением того, чтобы он не мог, например, добавлять десятки лишних разрывов строк между абзацами.
См. также раздел «Стилизация с помощью CSS» ниже.
Поддержка языков
EmailReplyTrimmer в настоящее время имеет полную или частичную поддержку 13 языков:
Английский, норвежский, французский, немецкий, португальский, испанский, итальянский, голландский, шведский, китайский, русский, польский, украинский
В отличие от этого, API обработки электронной почты FWD:Everyone в настоящее время поддерживает более 30 языков, включая все языки, которые в настоящее время поддерживаются в Discourse:
Английский, испанский, португальский, каталонский, голландский, французский, немецкий, итальянский, норвежский, датский, шведский, финский, русский, польский, украинский, турецкий, чешский, румынский, венгерский, иврит, арабский, персидский, китайский, японский, корейский, хинди, индонезийский, тайский, филиппинский, африкаанс
API обработки электронной почты FWD:Everyone полностью поддерживает языки с направлением письма справа налево (RTL). Это означает, что не только текст будет правильно отображаться справа налево в таких языках, как арабский, но также к HTML-разметке будут применяться соответствующие атрибуты, чтобы такие функции, как маркированные списки, отображались на правильной стороне страницы.
API иногда также работает на дополнительных языках в зависимости от используемого почтового клиента, но официальный поддерживаемый набор языков как минимум протестирован на работоспособность с Gmail, Outlook и Apple Mail. Менее популярные почтовые клиенты явно тестируются на языках, где они наиболее распространены. А поскольку API тестируется на тысячах цепочек писем из публичных рассылки, существует множество исправлений для реального хаотичного поведения неизвестного происхождения.
Обратите внимание, что поддержка широкого спектра языков важна не только для отображения текста на этих языках. Очень часто люди пишут текст на английском, но их почтовый клиент настроен, например, на иврит. Поэтому в таких случаях правильная обработка английского ответа потребует не только полной поддержки иврита, но и поддержки языков с направлением письма справа налево в целом.
Поддержка языков из широкого спектра языковых семей также помогает обеспечить правильную обработку и хранение Unicode, а не способами, которые могут вызвать проблемы в будущем по мере добавления поддержки большего количества не западных языков.
Стилизация с помощью CSS
Как упоминалось выше, ключевым преимуществом нашего API является его способность нормализовать HTML-разметку продуманным и логичным образом. Этот процесс нормализации разработан для оптимизации текста для читаемости и доступности, при этом максимально сохраняя оригинальные намерения автора.
Таким образом, весь текст появляется только внутри строчных или блочных элементов (нет свободно плавающего текста), и все строчные элементы появляются только внутри блочных элементов. Это упрощает стилизацию текста, например, для обеспечения правильного количества пробелов между различными элементами.
В качестве примера того, насколько это ценно, почтовые клиенты позволяют пользователям делать глупые вещи, например, вставлять маркированный список непосредственно перед или после строки текста без разрыва строки между ними. Код (сильно упрощенный), генерируемый почтовым клиентом при этом, может выглядеть примерно так:
<div>
Какой-то текст
<div> </div>
<span> • Маркированный пункт</span>
<div> </div>
Еще какой-то текст
</div>
API обработки электронной почты FWD:Everyone затем нормализует приведенную выше разметку, чтобы она выглядела так:
<p>Какой-то текст</p>
<ul>
<li>Маркированный пункт</li>
</ul>
<p>Еще какой-то текст</p>
Такая нормализованная разметка легко понимается и стилизуется, и визуально теперь также есть разрывы строк до и после маркированного списка. Подобные удобства делают текст более привлекательным и легким для чтения, сохраняя при этом намерения автора. Такие пользовательские удобства гарантируют, что отличный контент, отправленный по электронной почте, последовательно повышает социальный статус, а не подрывает его.
Упрощенная нормализованная разметка, генерируемая нашим API, также гарантирует, что при рассмотрении вопроса о том, как стилизовать текст, дизайнерам и разработчикам нужно думать только о том, какой вывод разрешен API, а не о том, как могло быть отформатировано исходное письмо. А поскольку разрешенный вывод из API практически идентичен тому, что разрешен веб-клиентом Discourse, это должно быть практически готовым решением для интеграции.
Предлагаемая интеграция
Функциональность «ответ по электронной почте» будет интегрирована с Discourse в виде плагина, который затем может быть включен по умолчанию для всех размещенных экземпляров Discourse.
Существующий код обработки электронной почты будет использоваться для экземпляров Discourse, у которых этот плагин не включен.
Кроме того, в случае временной недоступности API обработки электронной почты FWD:Everyone входящие сообщения будут обрабатываться с использованием существующего кода обработки электронной почты. Затем, когда API снова станет доступен, любые сообщения, которые не редактировались через веб-интерфейс после публикации, могут быть повторно обработаны API.
Плагин также может быть доступен для самостоятельно размещенных экземпляров Discourse для опционального включения.
Для групп, мигрирующих с существующих рассылки на Discourse, каждая цепочка писем в рассылке также может быть обработана через API, но это, скорее всего, будет интегрировано в существующие скрипты и процессы миграции Discourse, а не реализовано через плагин.[2]
Тестирование API
API полностью доступен для тестирования любым пользователем, хотя для неаутентифицированных пользователей установлен очень низкий лимит запросов.
Для тех, у кого есть учетные записи Gmail, самые простые способы протестировать API:
- Перейти на https://www.prettyfwd.com и установить надстройку G Suite.
- Перейти на https://api-demo.fwdeveryone.com и использовать клиентский OAuth для работы с API.
Основные отличия этих двух веб-инструментов от самого API заключаются в том, что первые:
- Не будут обрабатывать цепочки, содержащие сообщения, оформленные с использованием HTML-таблиц.
- Не будут удалять предыдущие ответы в первом сообщении цепочки. (Например, если в цепочке более 100 сообщений, и Gmail разбивает её на несколько цепочек.)
Для прямого тестирования API через код существуют стартовые скрипты для Python и Ruby:
А вот соответствующая документация, включая известные проблемы и дорожную карту продукта:
[1] Viewing American class divisions through Facebook and MySpace.
[2] При пакетном импорте контента из существующей рассылки стоит сначала провести быструю проверку на нескольких цепочках писем, чтобы убедиться, что они обрабатываются правильно. Некоторые группы будут обрабатываться с почти идеальной точностью как есть, но другие могут значительно выиграть от нескольких часов превентивной работы. Например, для некоторых программ рассылки требуется немного пользовательского кода для каждого списка, чтобы удалить любой текст, добавленный в конец каждого сообщения, тогда как для других программ рассылки это можно сделать предсказуемым образом, который будет работать для любого списка, размещенного на этой платформе. Из-за потенциальных проблем, подобных этим, процесс пакетного импорта следует предпочтительно запускать в рамках контролируемой миграции, а не через плагин.