Треды, или цепочки писем, всегда были одной из самых желаемых фич в Почте Mail.Ru, при условии, что опрос «Какого функционала вам не хватает?» проводился среди продвинутой аудитории (например, среди программистов или хабраюзеров). Вторая по популярности фича среди гиков — это, пожалуй, двухфакторная аутентификация, но о ней в отдельном посте.

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

Тем не менее, нам самим (команде Почты Mail.Ru), как людям, относящимся к первой группе (гики, любители продуктивити и программисты), идея тредов была близка и понятна. Поэтому мы решили пойти навстречу пожеланиям продвинутого сообщества и реализовать треды в опциональном режиме (включить их можно в меню «Вид» в правом верхнем углу над списком писем).



Однако легко решить, но не так легко сделать. На этапе продумывания логики обнаружилась масса нюансов. Хотя треды уже были реализованы в других почтовых службах, нам все равно пришлось разрабатывать собственный алгоритм. Во-первых, какие-то чужие решения нам казались ошибочными, и мы решили их исправить, во-вторых, логика работы некоторого базового функционала нашей почты отличается от работы похожего функционала у других, поэтому просто «перенять опыт» as is невозможно.

В этом посте мы хотим рассказать о том, какие трудности нас ждали и как нам удалось их преодолеть.

1. Как «склеивать» треды


1.1 Разбираемся с In-Reply-To

У каждого письма есть метаинформация (служебные заголовки). Заголовок In-Reply-To указывает, ответом на какое письмо является открытое вами сообщение (In-Reply-To), а References содержит, в том числе, информацию о письме, которое было первым в переписке. Логично, что если такие служебные заголовки есть, то имеет смысл группировать письма по этим заголовкам. Однако существуют два нюанса, которые нам надо было учесть.

Первый: как поступать с перенаправленными письмами? В случае, когда пришедшее письмо перенаправляется, на самом деле появляется еще одно письмо со служебным заголовком In-Reply-To. Этот заголовок указывает на перенаправляемое письмо. При этом в теме появляется приставка FW или FWD. То есть, по сути, форвард — это еще один ответ. Руководствуясь этой логикой, Gmail, например, «приклеивает» перенаправленные письма к той же цепочке.

Мы опросили пользователей внутри Mail.Ru и вовне и выяснили, что, как правило, пересылают письмо не для того, чтобы подключить человека к переписке, а чтобы обсудить с ним тему переписки отдельно. Значит — хотят начать новый «разговор», а не остаться в старом. Поэтому мы решили, что в таких случаях будем заводить новую цепочку.



Второй: иногда люди могут отвечать на письмо, изменив его тему вручную. Тогда в служебном заголовке письма формально останется пометка In-Reply-To, но тема письма изменится. Ориентируясь на результаты наших исследований, мы поняли, что если люди осознанно меняют тему письма, значит, для них это новая цепочка, и решили, что в таких случаях тоже будем создавать отдельный тред, даже несмотря на наличие In-Reply-To в служебном заголовке.

Исходя из этих двух нюансов, алгоритм группировки должен быть таким:
  • нормализуем тему, например, выкидываем все приставки «Re», но оставляем «FWD»
  • группируем письма, связанные заголовками и с одной нормализованной темой

1.2 Продумываем группировку для автоматических рассылок

Если заголовков нет, это еще не значит, что нечего группировать. Есть множество писем, которые так и просятся в одну группу: уведомления от соцсетей, промо-письма от интернет-магазинов, письма от таск-трекера, наконец. Как правило, во всех этих случаях у писем одна тема и один отправитель. Поэтому письма без заголовков мы решили группировать по критерию «тема + отправитель», чтобы охватить автоматические рассылки.



1.3 Отделяем «Корзину»

Отдельную проблему при реализации тредов создает папочная структура Почты. Мы решили, что в одну цепочку могут попадать письма из разных папок, в том числе из «Отправленных», чтобы в одном месте можно было увидеть и пришедшие письма, и ответы на них. Туда же по идее должны были попадать и письма из папки «Корзина». Изначально мы руководствовались такой логикой, однако первые бета-тестеры дали нам фидбек, что это неудобно и что они не хотят видеть удаленные письма, даже если по заголовкам они могли бы быть сгруппированы с письмом в папке «Входящие».

1.4 Определяемся с показаниями счетчиков

Как мы уже сказали, при группировке письма из одной цепочки могут быть разбросаны по разным папкам (cамый простой случай — это «Входящие» и «Отправленные»). В связи с этим возникает масса вопросов, например:
  • Если цепочка не прочитана, остается ли она непрочитанной во всех папках?
  • Если в цепочке несколько непрочитанных писем, что должен показывать счетчик — количество непрочитанных писем или одну непрочитанную цепочку?

У нас получается три варианта. Давайте их рассмотрим.

Первый: счетчик работает с цепочками, и непрочитанная цепочка отмечена во всех папках, в которых она отображается. Скажем, в двух папках — «Входящие» и «Отправленные» — есть одно непрочитанное письмо, которое только что пришло в ящик. В списке папок мы будем видеть по единице в каждой из этих двух папок. Но что показывать в общем счетчике у ящика? По идее, там надо отображать сумму для всех папок, а в нашем случае это два. Но ведь на самом деле в ящике одна непрочитанная цепочка!

Второй вариант: тред в папке считается непрочитанным, только если в папке есть непрочитанные письма из этого треда. Но предположим, что в треде два непрочитанных письма. Счетчик папки отображает единицу: не прочитан один тред. Пользователь открывает тред и читает верхнее письмо, после чего возвращается к списку писем. Одно письмо прочитано, но счетчик по-прежнему показывает единицу: ведь в треде есть еще одно непрочитанное письмо, а значит, и весь тред не прочитан. Получается, что пользователь совершил действие, а показания счетчиков не изменились.

Третий вариант, который мы и выбрали: в счетчиках учитываем именно письма, а не треды. В этом случае счетчик у каждой папки отображает верные данные, ведь письмо не может быть в нескольких папках. Общий счетчик тоже всегда отображает правильное число. Интерфейс в этом случае реагирует на прочтение любого письма изменением показаний счетчика.



Резюмируем:
  • треды мы склеиваем по заголовкам и теме или по отправителю и теме
  • пересланное письмо начинает новый тред
  • в тред входят письма из всех папок, кроме «Корзины»
  • в счетчиках папок отображаем количество непрочитанных писем, а не тредов

2. Внешний вид треда и действия с ним


2.1 Три уровня или два?

Базово на рынке существуют два вида отображения тредов:

Первый — при клике на тред в списке тредов открывается еще один список, на сей раз уже писем, где, чтобы добраться до прочтения конкретного письма, нужно обязательно кликнуть еще раз. Для удобства мы называли его «трехуровневым». Он применяется, кстати, много где — от некоторых версий Outlook до большого количества мобильных почтовых клиентов.

Второй (он же «двухуровневый») — при клике из списка тредов пользователь попадает сразу к «телам» писем, т.е. имеет возможность максимально быстро добраться до актуального содержимого переписки.

Мы решили не стоять на пути пользователя к его контенту и не заставлять его делать два клика каждый раз, когда он хочет прочитать вновь пришедшее письмо. Как вы уже догадались, был выбран «двухуровневый» вариант. Хотя он и технически и идеологически предвещал гораздо больше проблем, но о них чуть дальше.

2.2 Прочитанные и непрочитанные письма внутри треда

Тут мы решили не мудрствовать лукаво — очевидно, что пользователю интересно в первую очередь ознакомиться с содержанием тех писем, которые он еще не видел. А следовательно, на них и нужно акцентировать его внимание. Поэтому внутри треда мы решили разворачивать все непрочитанные письма, а все прочитанные оставлять свернутыми.

Если в треде нет непрочитанных писем, мы оставляем развернутым самое последнее (зачем — об этом чуть дальше).



2.3 Прочитанные и непрочитанные треды в списке тредов

Первый вопрос, который предстояло решить: помечать ли тред непрочитанным в списке писем (теперь уже в списке тредов), если там есть хоть одно непрочитанное письмо? Допустим, мы решим помечать тред непрочитанным. Но в случае, если письма одного и того же треда находятся в разных папках (например, часть — во «Входящих» и часть — в «Важных»), у нас появляются сразу две проблемы. Первая — помечая тред прочитанным в одной папке, мы меняем счетчик непрочитанных писем сразу в двух папках. Вторая — непонятно, что делать с общим счетчиком непрочитанных писем. Ведь если пользователь зайдет в ящик, увидит, что непрочитанные письма есть сразу в двух папках, откроет тред в первой папке и прочитает его, а при этом обнулятся оба счетчика, то он подумает, что второе непрочитанное письмо просто потерялось.

Мы отмели этот вариант как неудачный и решили попробовать поступить по-другому: помечать тред непрочитанным только в той папке, где у пользователя есть непрочитанные письма. Например, письма треда рассредоточены между «Входящими» и «Важными», при этом единственное непрочитанное письмо лежит в «Важных». То есть если пользователь находится во «Входящих» (где нет непрочитанных писем), все треды помечены как прочитанные.

Однако тут возникла еще одна небольшая проблема — когда пользователь открывает тред из Входящих, уже внутри он видит, что в нем есть развернутое непрочитанное письмо (то самое, которое лежит в «Важных»). Получается немного нелогично.

Эту проблему мы решили устранить следующим образом: письма из других папок в треде тоже будут свернуты до состояния заголовка, даже если они не прочитаны. Итак, попадая в тред, пользователь видит развернутыми только непрочитанные письма из данной папки. Таким образом, у нас нет лишней информации и нет «случайных» прочтений того, что должно было напоминать о себе (не зря же была настроена сортировка в отдельную папку).

Однако, справедливости ради, надо сказать, что ситуация, когда письма из одного треда находятся в разных папках (не считая Отправленных, конечно) встречается довольно редко. И это хорошо!

2.4 Удаление тредов

Одновременно с этим нам предстояло найти ответ еще на один вопрос. Представим ситуацию: мы находимся в папке «Входящие» и открываем тред, в котором одно письмо из папки «Входящие», а второе — из папки «Отправленные». Если нажать «Удалить тред», что произойдет с письмом из «Отправленных»? Опросив пользователей, мы выяснили: они ожидают, что письмо останется в папке «Отправленные». Поэтому у нас все действия с тредом — удаление, перемещение и т.п. — применяются только к письмами из папки, которую открыл пользователь.

2.5 Положение новых писем в треде

Еще один важный вопрос, который необходимо было решить: вверху или внизу цепочки показывать последние письма? Мы решили сохранить принцип, по которому работает классическая электронная почта, то есть самые свежие письма показывать сверху в треде (в отличие, например, от Gmail, где новые письма отображаются внизу треда).

Кроме того, наши исследования показали, что многие пользователи начинают читать тред с последнего письма, чтобы понять, стоит ли читать остальные письма в цепочке. Это стало еще одним аргументом в пользу отображения новых писем сверху.

2.6 Функциональность тулбара

Также необходимо было решить, как будет работать тулбар с кнопкой «Ответить», относящийся ко всему треду. Мы выбирали между двумя вариантами: повесить на него ответ и пересылку применительно к последнему письму в треде, либо к письму, которое в данный момент находится у пользователя на экране. В итоге мы остановились на первом варианте, поскольку вариант с письмом, находящимся в данный момент на экране вносил слишком много неопределенности, например, что делать, если на экране сразу два или даже три коротких письма? Или как интуитивно подсказать пользователю, на какое именно письмо он сейчас ответит?

Кстати, именно поэтому последнее письмо в треде всегда развернуто независимо от того, прочитано оно или нет. На тот случай, если у пользователя возникнет желание ответить на любое другое письмо, мы сделали небольшой дополнительный тулбар внутри треда, позволяющий это сделать.



Резюмируем:
  • самое актуальное письмо из текущей папки всегда развернуто
  • письма из других папок свернуты независимо от статуса
  • письма из текущей папки свернуты, только если прочитаны
  • при удалении треда удаляем только письма из текущей папки
  • самые свежие письма отображаем сверху
  • кнопки на верхнем тубларе в треде работают с верхним письмом

***

Реализация тредов в почте — довольно сложная задача, на решение которой мы потратили немало времени и сил. Сейчас треды можно включить во всех ящиках Почты Mail.Ru.

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