Ответ по электронной почте из Outlook удаляет всё после нумерованного списка

Самохостинг, версия 2026.1.5 (коммит 2727e4d). Мы ведём сообщество в режиме рассылки и принимаем ответы по электронной почте.

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

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

Проблема в методе extract_from_word в файле lib/email/receiver.rb. Для писем из Outlook/Word он рассматривает первого дочернего элемента .WordSection1, который не является <p> или <ul>, как начало подписи или пересланного сообщения, и удаляет его вместе со всеми последующими соседними элементами:

elided =
doc.css(
“.WordSection1 > :not(p):not(ul):first-of-type, .WordSection1 > :not(p):not(ul):first-of-type ~ *”,
).remove

Outlook рендерит нумерованные списки как <ol>, а в селекторе <ol> не исключён. Таким образом, нумерованный список становится первым элементом, который не является <p> или <ul>, и приёмник обрывает сообщение именно в этом месте. Маркированные списки (<ul>) исключены, поэтому они сохраняются, а нумерованный — нет.

Воспроизведение

  1. В Outlook (настольная версия) ответьте на уведомление. Напишите абзац, затем нумерованный список, затем ещё один абзац.
  2. Созданный пост сохраняет текст до нумерованного списка и отбрасывает сам список и всё, что находится ниже него.

Минимальное HTML-тело, которое вызывает проблему (легко добавить в тест приёмника):

Вводный абзац.

Шаги:

  1. Первый
  2. Второй

Этот завершающий абзац тоже исчезает.

В результате вы получаете только два вводных абзаца.

Проблема всё ещё присутствует в ветке main — селектор не менялся. Я сначала поискал в категории багов, но не нашёл уже зарегистрированной такой проблемы.

Предлагаемое исправление

Относиться к <ol> так же, как к <ul>, поскольку нумерованный список — это содержимое, а не подпись:

“.WordSection1 > :not(p):not(ul):not(ol):first-of-type, .WordSection1 > :not(p):not(ul):not(ol):first-of-type ~ *”

Это сохранит список и при этом всё ещё будет удалять реальные маркеры подписи/пересылки (таблицы, div, hr, изображения). Готов открыть PR с тестовым письмом и падающим тестом, если это поможет.

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

Хм. В панели администратора Discourse указано, что я использую последнюю версию и всё обновлено. Очень странно.