Необъяснимые ошибки Unexplained Email::Receiver::InvalidPost

Несколько списков рассылки зеркально дублируются по адресу https://forum.torproject.org/c/mailing-lists/23

Недавно мы заметили, что некоторые сообщения из списка рассылки Mailman3 не дублируются на форум.

Логи отклонения электронной почты показывают, что эти письма столкнулись с ошибкой Email::Receiver::InvalidPost.

Сообщение об ошибке, зафиксированное в логах, соответствует одному из двух вариантов:

Извините, но ваше электронное письмо на адрес [“tor-relays@lists.torproject.org”] (с заголовком [tor-relays] authority bandwidth measurements and latency) не было доставлено.

Причина:

Доступ запрещён

Если вы можете устранить проблему, пожалуйста, попробуйте снова.

или:

Извините, но ваше электронное письмо на адрес [“tor-relays@lists.torproject.org”] (с заголовком [tor-relays] Re: webtunnel bridges for the telegram distributor) не было доставлено.

Причина:

Что-то пошло не так. Возможно, эта тема была закрыта или удалена, пока вы её просматривали?

Если вы можете устранить проблему, пожалуйста, попробуйте снова.

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

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

1 лайк

Включена ли опция «принимать письма от анонимных аккаунтов» в настройках каждой категории? И, пожалуйста, пришлите лог электронной почты Discourse (по возможности с частичным удалением конфиденциальных данных).

1 лайк

Да, могу подтвердить, что эта настройка включена.

и, пожалуйста, отправьте лог отправки писем Discourse (возможно, с небольшой цензурой)

Нужно ли мне извлекать это из контейнера или с хоста? Мы также обрабатываем почту через контейнер mail-receiver. Или вы хотите логи, которые отображаются в веб-интерфейсе (например, /admin/email-logs/rejected)?

Это пришло из Exchange?

Иногда Microsoft Exchange отправляет мусор, если он неправильно настроен и думает, что общается с… Не уверен — с другим сервером Exchange? Или чем-то ещё в собственной инфраструктуре?

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

mid = 'message-id из лога'
puts IncomingEmail.find_by(message_id: mid).raw

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

This is a multi-part message in MIME format.
--=====003_Dragon855807841081_=====
Content-Type: text/plain;
 charset=utf-8
Content-Transfer-Encoding: base64

7bgir+m+vzzIDCLE0mDmZrfIXvvmXjY=

--=====003_Dragon855807841081_=====
Content-Type: text/html;
 charset=utf-8
Content-Transfer-Encoding: base64

LP/0L4tqmfZizO0DCDDE10uOzMZqzSHDjq04SLPaBjibLVHz+V94m1M45NDN
55aM8SMIf9XY4EFjP9CCFz+ojfmJqmubaz+bjrzmubw+bjWTiGSuLg==

--=====003_Dragon855807841081_=====--

так как части не декодируются в корректный текст.

2 лайка

Оба варианта были бы замечательны. Если вы используете PuTTY SSH, вы можете извлечь логи контейнера и сделать скриншот интерфейса Discourse. Однако в фотографии слова сложно найти для редактирования :face_exhaling:

Мне удалось извлечь два письма с полными заголовками. Один MUA — это Apple Mail, а другой — Claws Mail.

Я с радостью перешлю их на чью-либо личную электронную почту для отладки, чтобы не размещать их по всему Интернету.

Полагаю, что в обоих случаях, скорее всего, проблема в том, что Discourse некорректно обрабатывает содержимое письма.

Для информации, это всё ещё проблема. Discourse регулярно отбрасывает сообщения из рассылки от различных отправителей с ошибкой Email::Receiver::InvalidPost по причинам, которые я не могу выяснить.

Если вы нажмёте на ошибку в логах, отобразится ли причина отказа в сообщении об отказе?

Например:

Если вы нажмёте на ошибку в логах, показывает ли она причину отклонения в поле «Причина отклонения»?

Эти сообщения бывают двух типов:

Нам очень жаль, но ваше электронное письмо на адрес ["tor-relays@lists.torproject.org"] (с темой [tor-relays] Re: abuse report from relays in family 7EAAC49A7840D33B62FA276429F3B03C92AA9327) не было доставлено.

Причина:

Произошла ошибка. Возможно, эта тема была закрыта или удалена, пока вы её просматривали?

Если вы можете устранить проблему, пожалуйста, попробуйте снова.

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

В некоторых других случаях в поле «Причина» просто указано Access Denied (Отказано в доступе).

Редактирование: сообщения такие же, как я описал в своём первоначальном посте.

Привет, lavamind — извините, что поднимаю старую тему, но прежде чем углубляться в отладку, хотел бы сначала уточнить несколько моментов.

Вы всё ещё сталкиваетесь с отклонениями Email::Receiver::InvalidPost при зеркальном копировании списков рассылки на данный момент (конец 2025 / начало 2026 года)?

Если да, могли бы вы кратко описать:

  • как часто это происходит (например, ежедневно / еженедельно, процент сообщений)
  • остаётся ли основная причина отклонения в письме «Access Denied» или же это «topic closed/deleted»
  • затрагивает ли это один список/категорию или несколько

Как только мы подтвердим, что проблема всё ещё актуальна, мы перейдём к сбору минимального набора диагностических данных для одного недавнего сбоя (Message-ID + соответствующее сохранённое исходное письмо и т. д.).

Извиняться не нужно, я очень рад, что вы занимаетесь этим вопросом.

Привет, lavamind — извините, что всплываю в старой теме, но прежде чем углубляться в отладку, хотел бы сначала связаться с вами.

Вы всё ещё сталкиваетесь с отклонениями Email::Receiver::InvalidPost при зеркальном отражении рассылки на данный момент (конец 2025 / начало 2026)?

Да, проблема всё ещё сохраняется.

как часто это происходит (например, ежедневно / еженедельно, % сообщений)

Точную частоту определить сложно, но проблема затрагивает как минимум несколько сообщений в неделю, ориентировочно где-то между 5 и 10% сообщений? Некоторые отправители, похоже, чаще фигурируют в журналах ошибок, так что, по крайней мере, это выглядит не совсем случайно.

остаётся ли основная причина отклонения письма «Access Denied» или «тема закрыта/удалена»

По-прежнему встречается смесь обоих вариантов.

затрагивает ли это один список/категорию или несколько

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

После подтверждения, что проблема всё ещё существует, мы можем перейти к сбору минимального набора диагностических данных для одного недавнего сбоя (Message-ID + соответствующее сохранённое исходное письмо и т. д.).

Мы могли бы рассмотреть эту недавнюю тему. Архив Mailman указывает, что было получено 5 сообщений, но зеркальная тема на форуме содержит только 3 сообщения. В журналах отклонений для этой темы зафиксировано 3 ошибки InvalidPost (2 от одного и того же отправителя, странно), и для всех них указан причина отклонения: «Что-то пошло не так. Возможно, эта тема была закрыта или удалена, пока вы её просматривали?»

Спасибо, lavamind — это действительно полезный ориентир, особенно когда есть конкретная ветка «Архив Mailman показывает 5, тема форума — 3», на которую можно опереться.

Учитывая, что вы сталкиваетесь с этим несколько раз в неделю (примерно 5–10 % сообщений) и что в данном случае причина возврата постоянно связана с вводящим в заблуждение вариантом «тема закрыта/удалена», следующим лучшим шагом будет захват одного неудачного сообщения от начала до конца, чтобы мы могли увидеть, что именно Discourse считал, что делает.


Для одного из трёх отклонённых писем, связанных с темой-зеркалом, пожалуйста, предоставьте следующее:

  1. В разделе /admin/email-logs/rejected откройте одну из строк InvalidPost для данного инцидента и скопируйте:

    • Message-ID
    • дату/время
    • (замазанные) поля To / From / Subject, показанные в строке
    • полный текст причины возврата (как отображается)
  2. В консоли Rails (в контейнере приложения Discourse) извлеките исходное письмо, сохранённое Discourse:

@supermathie, остаётся ли IncomingEmail каноническим местом для получения исходного письма и нужно ли что-то ещё для отладки InvalidPost?

mid = "<вставьте Message-ID из лога отклонённых писем>"
ie  = IncomingEmail.find_by(message_id: mid)

puts ie&.raw
  1. Также извлеките атрибуты EmailLog для того же Message-ID (это часто позволяет понять, рассматривал ли Discourse письмо как ответ или новую тему, а также какие ID темы/категории были разрешены):
mid = "<тот же Message-ID, что и выше>"

log = EmailLog.where(message_id: mid).order(created_at: :desc).first
pp log&.attributes&.slice(
  "id",
  "email_type",
  "to_address",
  "from_address",
  "subject",
  "post_id",
  "topic_id",
  "user_id",
  "status",
  "bounce_error_code",
  "bounce_key",
  "created_at"
)

Зачем нужен этот набор?

  • IncomingEmail.raw покажет, пришло ли письмо с ошибками/некорректным кодированием/только с подвалом, либо Discourse выбрал «неправильную» MIME-часть.
  • EmailLog покажет, что именно пытался сделать Discourse (новая тема или ответ, разрешённые ID темы/категории и т. д.).
  • строка в интерфейсе отклонённых писем подтверждает, что мы смотрим на тот же инцидент, и сохраняет то, что видят операторы.

Если есть вопросы конфиденциальности, вы можете замазать адреса и любой текст тела письма внутри raw, но, пожалуйста, сохраните:

  • MIME-заголовки (Content-Type, границы, charset, Content-Transfer-Encoding)
  • структуру multipart (чтобы мы видели, какие части присутствуют)
  • Message-ID и базовые заголовки маршрутизации (домены при необходимости можно замазать)

Как только у нас будет один неудачный Message-ID + IncomingEmail.raw + срез EmailLog, мы сможем быстро определить, является ли проблема:

  • несоответствием ключа ответа / маршрутизации темы,
  • пограничным случаем с правами доступа,
  • или сбоем парсинга письма / выбора MIME-части / декодирования.

Спасибо за очень подробное руководство!

Давайте сосредоточимся на этом сообщении, отправленном в тему рассылки.

Заголовки инцидента с журналом отклонённых постов показывают следующее:

Message-ID: <20260103080033.5f6d8f90@dorfdsl.de>
Date: Sat, 03 Jan 2026 08:00:33 +0100
From: Marco Moock via tor-relays <tor-relays@lists.torproject.org>
To: tor-relays@lists.torproject.org
Subject: [tor-relays] Re: Questions about running an exit relay

Полный текст причины отклонения таков:

Приносим извинения, но ваше электронное письмо на адрес ["tor-relays@lists.torproject.org"] (с заголовком [tor-relays] Re: Questions about running an exit relay) не было доставлено.

Причина:

Произошла ошибка. Возможно, эта тема была закрыта или удалена, пока вы её просматривали?

Если вы можете устранить проблему, пожалуйста, попробуйте снова.

Текстовая запись электронного письма, отправленного в Discourse через Mailman (IncomingEmail), доступна здесь (я не считаю, что она содержит какие-либо данные, которые ещё не были общедоступны, но в любом случае я установил срок действия этой ссылки).

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

Спасибо @lavamind — это отлично (Message-ID + текст отказа + копия того, что сохранил Discourse).

Также: моя ошибка по поводу запроса EmailLog — вполне вероятно (и, возможно, ожидаемо), что для входящего отказа, как этот, записи EmailLog нет. EmailLog предназначен в основном для исходящей почты, тогда как входящая хранится в IncomingEmail (который вы уже извлекли). @supermathie, не могли бы вы подтвердить, что я не веду людей по неверному пути?

Поскольку у нас есть IncomingEmail, не могли бы вы привести поля метаданных из той же записи? Это должно дать нам контекст «что пытался сделать Discourse?», на который я надеялся получить из EmailLog.

В консоли Rails:

# @supermathie проверка на здравый смысл: при отладке входящих InvalidPost, является ли метаданные IncomingEmail следующим правильным шагом для сбора?

mid = "<20260103080033.5f6d8f90@dorfdsl.de>"
ie  = IncomingEmail.find_by(message_id: mid)

pp ie&.attributes&.slice(
  "id",
  "message_id",
  "from_address",
  "to_addresses",
  "cc_addresses",
  "subject",
  "created_at",
  "user_id",
  "post_id",
  "topic_id",
  "error"
)

# опционально: если вам удобно, это тоже часто полезно
# (показывает, что Discourse извлек как тело сообщения по сравнению с тем, что сохранил в сыром виде)
pp ie&.attributes&.slice("raw", "cooked")

(Если raw/cooked очень большие, можете их опустить — вы уже поделились сырым вариантом.)

Почему эти поля важны:

  • topic_id / post_id (если присутствуют) говорят нам, определил ли Discourse это как ответ/новый пост и на что он был направлен.
  • user_id указывает, какому временному/реальному пользователю Discourse сопоставил отправителя (случаи с правами доступа / «Доступ запрещен»).
  • error часто более конкретен, чем общий текст отказа «тема закрыта/удалена».

Если эти атрибуты показывают разрешение topic_id/post_id, указывающее на зеркальную тему, то следующим вероятным шагом будет выяснение, почему получатель решил, что это недействительно (пустое извлеченное тело, декодирование MIME, несоответствие прав доступа, несоответствие ключа ответа и т. д.). Если не показано никакого разрешения topic/post вообще, мы сосредоточимся на заголовках маршрутизации / обнаружении ответов.

И снова — спасибо за ссылку на вставку. Наличие одного конкретного ошибочного Message-ID, такого как этот, — это именно то, что нам нужно, чтобы перестать гадать.

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

1 лайк

Вот поля метаданных для IncomingObject

{"id"=>9785,
"message_id"=>"20260103080033.5f6d8f90@dorfdsl.de",
"from_address"=>"mm@dorfdsl.de",
"to_addresses"=>"tor-relays@lists.torproject.org",
"cc_addresses"=>"",
"subject"=>"[tor-relays] Re: Questions about running an exit relay",
"created_at"=>2026-01-03 07:03:04.639775000 UTC +00:00,
"user_id"=>10477,
"post_id"=>nil,
"topic_id"=>nil,
"error"=>"Email::Receiver::InvalidPost"}

Что касается необработанного/обработанного содержимого, то только свойство raw содержит полное письмо с заголовками. Свойство cooked в объекте отсутствует.

Выполнение команды Email::Receiver.new(rawmessage).select_body возвращает:

=> ["", "", 2]

Таким образом, я почти уверен, что происходит следующее: Discourse ошибочно выбирает пустую часть в формате plain/text в качестве тела сообщения, вероятно, эту:

--Sig_/gizYC_1dGsAzUHvksdaMIe2
Content-Type: text/plain;
 charset=UTF-8
Content-Transfer-Encoding: 7bit


что привело бы к созданию некорректного сообщения.

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

Структура письма следующая:

* #<Mail::Part:39500, Multipart: false, Headers: <MIME-Version: 1.0>, <Content-Type: text/plain; charset=us-ascii>, <Content-Transfer-Encoding: 7bit>, <Content-Disposition: inline>, <Content-ID: <6958bf289b75c_b28a46298091029@forum-01-app.mail>>>  "___…tor-relays mailing list…"
* #<Mail::Part:39520, Multipart: true, Headers: <Content-Type: multipart/signed; boundary="Sig_/gizYC_1dGsAzUHvksdaMIe2"; micalg=pgp-sha256; protocol="application/pgp-signature">, <Content-Transfer-Encoding: 7bit>>
  * #<Mail::Part:39540, Multipart: false, Headers: <Content-Type: text/plain; charset=US-ASCII>, <Content-Transfer-Encoding: quoted-printable>>,
    "On 02.01.2026…"
  * #<Mail::Part:39560, Multipart: false, Headers: <Content-Type: text/plain; charset=UTF-8>, <Content-Transfer-Encoding: 7bit>>,
    ""
  * #<Mail::Part:39580, Multipart: false, Headers: <Content-Type: text/plain; charset=US-ASCII>, <Content-Transfer-Encoding: quoted-printable>>,
    "On 02.01.2026…"
  * #<Mail::Part:39600, Multipart: false, Headers: <Content-Type: text/plain; charset=UTF-8>, <Content-Transfer-Encoding: 7bit>>,
    ""
  * #<Mail::Part:39620, Multipart: false, Headers: <Content-Type: text/plain; charset=US-ASCII>, <Content-Transfer-Encoding: quoted-printable>>,
    "On 02.01.2026…"
  * #<Mail::Part:39640, Multipart: false, Headers: <Content-Type: text/plain; charset=UTF-8>, <Content-Transfer-Encoding: 7bit>>,
    ""
  * #<Mail::Part:39660, Multipart: false, Headers: <Content-Type: text/plain; charset=US-ASCII>, <Content-Transfer-Encoding: quoted-printable>>,
    "On 02.01.2026…"
  * #<Mail::Part:39680, Multipart: false, Headers: <Content-Type: application/pgp-signature>, <Content-Description: Digitale Signatur von OpenPGP>>,
    PGP signature
  * #<Mail::Part:39700, Multipart: false, Headers: <Content-Type: application/pgp-signature>, <Content-Transfer-Encoding: 7bit>, <Content-Description: Digitale Signatur von OpenPGP>>,
    PGP signature
  * #<Mail::Part:39720, Multipart: false, Headers: <Content-Type: application/pgp-signature>, <Content-Transfer-Encoding: 7bit>, <Content-Description: Digitale Signatur von OpenPGP>>]
    PGP signature

(да, есть три копии основного содержимого, пустого содержимого и PGP-подписи)

Первая часть text/plain добавляется программным обеспечением рассылки и выглядит так:

_______________________________________________
tor-relays mailing list -- tor-relays@lists.torproject.org
To unsubscribe send an email to tor-relays-leave@lists.torproject.org

Именно это Discourse (на самом деле gem mail через .text_part) выбирает в качестве содержимого сообщения:

> puts mail.text_part.to_s
MIME-Version: 1.0
Content-Type: text/plain;
 charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
Content-ID: <6958bf289b75c_b28a46298091029@forum-01-app.mail>

_______________________________________________
tor-relays mailing list -- tor-relays@lists.torproject.org
To unsubscribe send an email to tor-relays-leave@lists.torproject.org

и рассматривает как пустое тело с удалённой подписью.

Если бы не эта в основном пустая часть, добавленная рассылкой, Discourse извлек бы для поста следующее содержимое:

> We received a court order to preserve the data on the system and were
> forbidden from informing the system owner, which was awkward since
> they had informed the system owner...

Which data did they request?

> Since then I've always run my exit on a separate system on it's own
> IP so if there were a legal demand to turn over "the system" it would
> really only be that system. I'm not a lawyer but I don't think docker
> provides enough isolation for that.

Can they deny you to turn the relay off?
If so, you could then operate a new "system" on another IP.

(ниже удалённая часть)

On 02.01.2026 18:46 Jon via tor-relays <tor-relays@lists.torproject.org> wrote:

-- 
kind regards
Marco

Send spam to abfall1767375998@stinkedores.dorfdsl.de

Я не могу найти недостатков в обработке почты Discourse здесь — если бы мне пришлось распределять ответственность, я бы, вероятно, начал с программного обеспечения рассылки, которое фактически добавляет пустое содержимое в начало. Это было бы лучше разместить в конце, после основного сообщения.

Это работало бы с gem Mail и выглядело бы лучше в почтовых клиентах — вот как это выглядит в Thunderbird при первоначальном получении:

и моя «исправленная» версия (test-fixed.eml.txt (14.3 KB))
с подписью рассылки внизу вместо верха:

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

Email::Receiver.new(IncomingEmail.find(INCOMING_EMAIL_ID).raw).select_body

Я связался с (человеческим) подписчиком этого списка, и вот как выглядит исходное тело сообщения в его почтовом клиенте (MUA) с отфильтрованными заголовками:

Subject: [tor-relays] Re: Questions about running an exit relay
List-Id: "support and questions about running Tor relays (exit, non-exit,
 bridge)" <tor-relays.lists.torproject.org>
Archived-At: 
 <https://lists.torproject.org/mailman3/hyperkitty/list/tor-relays@lists.torproject.org/message/OAX7EO72GLXS4KPKUG7QSG7EOAR2WYVA/>
List-Archive: 
 <https://lists.torproject.org/mailman3/hyperkitty/list/tor-relays@lists.torproject.org/>
List-Help: <mailto:tor-relays-request@lists.torproject.org?subject=help>
List-Owner: <mailto:tor-relays-owner@lists.torproject.org>
List-Post: <mailto:tor-relays@lists.torproject.org>
List-Subscribe: <mailto:tor-relays-join@lists.torproject.org>
List-Unsubscribe: <mailto:tor-relays-leave@lists.torproject.org>
From: Marco Moock via tor-relays <tor-relays@lists.torproject.org>
Reply-To: Marco Moock <mm@dorfdsl.de>
Content-Type: multipart/mixed; boundary="===============8958541500975114832=="

--===============8958541500975114832==
Content-Type: multipart/signed; boundary="Sig_/gizYC_1dGsAzUHvksdaMIe2";
 protocol="application/pgp-signature"; micalg=pgp-sha256

--Sig_/gizYC_1dGsAzUHvksdaMIe2
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: quoted-printable

On 02.01.2026 18:46 Jon via tor-relays
<tor-relays@lists.torproject.org> wrote:

> We received a court order to preserve the data on the system and were
> forbidden from informing the system owner, which was awkward since
> they had informed the system owner...

Какие данные они запросили?

> Since then I've always run my exit on a separate system on it's own
> IP so if there were a legal demand to turn over "the system" it would
> really only be that system. I'm not a lawyer but I don't think docker
> provides enough isolation for that.

Могут ли они запретить вам отключить релей?
Если да, то вы можете запустить новую «систему» на другом IP-адресе.

--=20
с наилучшими пожеланиями
Марко

Отправляйте спам на abfall1767375998@stinkedores.dorfdsl.de

--Sig_/gizYC_1dGsAzUHvksdaMIe2
Content-Type: application/pgp-signature
Content-Description: Digitale Signatur von OpenPGP

-----BEGIN PGP SIGNATURE-----

iQJPBAEBCAA5FiEEpXefSZn9R6zNZtTQE76RLz2tRfAFAmlYvpEbFIAAAAAABAAO
bWFudTIsMi41KzEuMTEsMiwyAAoJEBO+kS89rUXw8kgP/2jkrwfSWHY6EY4WJjn6
EDEqT00pgpwEn9ZpUqLTreS3/ocfHC4g29HIsxpJcj/bH+hNAx96HEz9YmC4JfEt
LDjYc6D+5NBBFQGy0vaJ/LXLQc63CRE/yySSOYxFBZK+uMytNHoZDTjhfRroICbQ
guoO7A4/VuYrGAzCWQkBUmnBjj2LJhuLDW84ObMXhA/EuNy5FIAqyLZxoGmFEfvu
We5d0Hr3+wihzyrgGiG4u8UGFOyL+/PC11CFQyQ0j03cBzhZ5PVdtkqPNHauAcjQ
Gt/HQmaOSGKq0VODRjiHAe5TuRtV6jOfUNgS1Q2vB4FKYmeDQb82ooNfOiJWy3ey
Jpwgg700ppqgZUclpMPlzxKwi2dT/PSO6yYuy+G5sfa0Hxmn5DsQaiSPMTiEP2WC
NwAENYIuHeQOHWiS8B3oVSRW/naLzkmpfChFnTKGsrhLqKQc/iuvv639aHwg9BP7
YEbWbdpFpIU36czfxoTcDYDR1e4JLWryEFKIgo4TIaz4t17NmkxjXB6dHZKLLAdU
AT6LmL6mOTaXe9ewD9pf9Vf2nG0RGVJyZRUDmFzfU0Rx2qi7KdcmmRpZg/2QtJeA
Pmrv8NFuFEL0BrhTvo7C60m+gjLaXPNClgKEN0vkEzjLp/ZKjI9FslP61xUMg8lQ
3xT/HTkNt9uNH2ziBMXLK+5c
=0Euf
-----END PGP SIGNATURE-----

--Sig_/gizYC_1dGsAzUHvksdaMIe2--

--===============8958541500975114832==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
tor-relays mailing list -- tor-relays@lists.torproject.org
To unsubscribe send an email to tor-relays-leave@lists.torproject.org

--===============8958541500975114832==--

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

Тогда я задаюсь вопросом, не влияет ли что-то ещё в конвейере обработки на тело сообщения. Наш сервер Discourse сначала обрабатывает входящие письма с помощью Postfix, который настроен на передачу их в контейнер mail-receiver, а тот, в свою очередь, передаёт их в контейнер Discourse.

О! Учитывая это, я вернулся и провёл повторное расследование… и оказалось, что проблема всё-таки на нашей стороне.

Из необработанного письма, которое вы опубликовали выше, я только что обнаружил, что IncomingEmail.raw на самом деле не хранит исходное письмо… мы сначала обрабатываем его через Email::Cleaner.

(извините, всё это время я думал, что можно ему доверять, раньше мы могли)

Похоже, что это вина Ruby mail gem… он переставляет части сообщения при повторной записи:

[1] pry(main)> m = File.open('test.eml').read;
[2] pry(main)> Mail.new(m).parts
=> [
  #<Mail::Part:39680, Multipart: true, Headers: <Content-Type: multipart/signed; boundary="Sig_/gizYC_1dGsAzUHvksdaMIe2"; protocol="application/pgp-signature"; micalg=pgp-sha256>>,
  #<Mail::Part:39700, Multipart: false, Headers: <MIME-Version: 1.0>, <Content-Type: text/plain; charset="us-ascii">, <Content-Transfer-Encoding: 7bit>, <Content-Disposition: inline>>
 ]
[3] pry(main)> Mail.new(Mail.new(m).to_s).parts
=> [
  #<Mail::Part:39720, Multipart: false, Headers: <MIME-Version: 1.0>, <Content-Type: text/plain; charset=us-ascii>, <Content-Transfer-Encoding: 7bit>, <Content-Disposition: inline>, <Content-ID: <6966b4914df79_31d5b1d38126@mars.mail>>>,
  #<Mail::Part:39740, Multipart: true, Headers: <Content-Type: multipart/signed; boundary="Sig_/gizYC_1dGsAzUHvksdaMIe2"; micalg=pgp-sha256; protocol="application/pgp-signature">, <Content-Transfer-Encoding: 7bit>>
]

что и вызывает проблему:

[38] pry(main)> puts Email::Receiver.new(m).select_body[0];
> Мы получили судебный приказ сохранить данные на системе и нам
> было запрещено сообщать владельцу системы, что было неловко, так как
> они уже сообщили владельцу системы...

Какие данные они запросили?

> С тех пор я всегда запускал свой выходной узел на отдельной системе на собственном
> IP-адресе, так что если бы был юридический запрос на передачу «системы», это
> касалось бы только этой системы. Я не юрист, но не думаю, что docker
> обеспечивает достаточную изоляцию для этого.

Могут ли они запретить вам отключить ретранслятор?
Если да, то вы можете запустить новую «систему» на другом IP.

[39] pry(main)> puts Email::Receiver.new(Mail.new(m).to_s).select_body[0];
«нет вывода»
Детали различий

test.eml: исходное сообщение, как было предоставлено
test-rubyparsed.eml: сообщение, распаршенное Ruby и снова преобразованное в строку
test-pythonparsed.eml: сообщение, распаршенное Python и снова преобразованное в строку

--- test.eml	2026-01-13 15:58:18.769489410 -0500
+++ test-rubyparsed.eml	2026-01-13 16:11:17.767312268 -0500
@@ -1,25 +1,46 @@
+Date: Tue, 13 Jan 2026 16:07:21 -0500
+From: Marco Moock via tor-relays <tor-relays@lists.torproject.org>
+Reply-To: Marco Moock <mm@dorfdsl.de>
+Message-ID: <6966b40914be8_31d5b1d38719@mars.mail>
 Subject: [tor-relays] Re: Questions about running an exit relay
+MIME-Version: 1.0
+Content-Type: multipart/mixed;
+ boundary="===============8958541500975114832=="
+Content-Transfer-Encoding: 7bit
 List-Id: "support and questions about running Tor relays (exit, non-exit,
  bridge)" <tor-relays.lists.torproject.org>
-Archived-At: 
- <https://lists.torproject.org/mailman3/hyperkitty/list/tor-relays@lists.torproject.org/message/OAX7EO72GLXS4KPKUG7QSG7EOAR2WYVA/>
-List-Archive: 
- <https://lists.torproject.org/mailman3/hyperkitty/list/tor-relays@lists.torproject.org/>
+Archived-At: <https://lists.torproject.org/mailman3/hyperkitty/list/tor-relays@lists.torproject.org/message/OAX7EO72GLXS4KPKUG7QSG7EOAR2WYVA/>
+List-Archive: <https://lists.torproject.org/mailman3/hyperkitty/list/tor-relays@lists.torproject.org/>
 List-Help: <mailto:tor-relays-request@lists.torproject.org?subject=help>
 List-Owner: <mailto:tor-relays-owner@lists.torproject.org>
 List-Post: <mailto:tor-relays@lists.torproject.org>
 List-Subscribe: <mailto:tor-relays-join@lists.torproject.org>
 List-Unsubscribe: <mailto:tor-relays-leave@lists.torproject.org>
-From: Marco Moock via tor-relays <tor-relays@lists.torproject.org>
-Reply-To: Marco Moock <mm@dorfdsl.de>
-Content-Type: multipart/mixed; boundary="===============8958541500975114832=="
+
+
+--===============8958541500975114832==
+MIME-Version: 1.0
+Content-Type: text/plain;
+ charset=us-ascii
+Content-Transfer-Encoding: 7bit
+Content-Disposition: inline
+Content-ID: <6966b40914ae9_31d5b1d38641@mars.mail>
+
+_______________________________________________
+tor-relays mailing list -- tor-relays@lists.torproject.org
+To unsubscribe send an email to tor-relays-leave@lists.torproject.org
 
 --===============8958541500975114832==
-Content-Type: multipart/signed; boundary="Sig_/gizYC_1dGsAzUHvksdaMIe2";
- protocol="application/pgp-signature"; micalg=pgp-sha256
+Content-Type: multipart/signed;
+ boundary="Sig_/gizYC_1dGsAzUHvksdaMIe2";
+ micalg=pgp-sha256;
+ protocol="application/pgp-signature"
+Content-Transfer-Encoding: 7bit
+
 
 --Sig_/gizYC_1dGsAzUHvksdaMIe2
-Content-Type: text/plain; charset=US-ASCII
+Content-Type: text/plain;
+ charset=US-ASCII
 Content-Transfer-Encoding: quoted-printable
 
 On 02.01.2026 18:46 Jon via tor-relays
@@ -39,7 +60,8 @@
 Can they deny you to turn the relay off?
 If so, you could then operate a new "system" on another IP.
 
---=20
+-- =
+
 kind regards
 Marco
 
@@ -47,6 +69,7 @@
 
 --Sig_/gizYC_1dGsAzUHvksdaMIe2
 Content-Type: application/pgp-signature
+Content-Transfer-Encoding: 7bit
 Content-Description: Digitale Signatur von OpenPGP
 
 -----BEGIN PGP SIGNATURE-----
@@ -69,14 +92,5 @@
 
 --Sig_/gizYC_1dGsAzUHvksdaMIe2--
 
---===============8958541500975114832==
-Content-Type: text/plain; charset="us-ascii"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Content-Disposition: inline
-
-_______________________________________________
-tor-relays mailing list -- tor-relays@lists.torproject.org
-To unsubscribe send an email to tor-relays-leave@lists.torproject.org
-
 --===============8958541500975114832==--
+
--- test.eml	2026-01-13 15:58:18.769489410 -0500
+++ test-pythonparsed.eml	2026-01-13 16:19:30.385608544 -0500
@@ -1,10 +1,8 @@
 Subject: [tor-relays] Re: Questions about running an exit relay
 List-Id: "support and questions about running Tor relays (exit, non-exit,
  bridge)" <tor-relays.lists.torproject.org>
-Archived-At: 
- <https://lists.torproject.org/mailman3/hyperkitty/list/tor-relays@lists.torproject.org/message/OAX7EO72GLXS4KPKUG7QSG7EOAR2WYVA/>
-List-Archive: 
- <https://lists.torproject.org/mailman3/hyperkitty/list/tor-relays@lists.torproject.org/>
+Archived-At: <https://lists.torproject.org/mailman3/hyperkitty/list/tor-relays@lists.torproject.org/message/OAX7EO72GLXS4KPKUG7QSG7EOAR2WYVA/>
+List-Archive: <https://lists.torproject.org/mailman3/hyperkitty/list/tor-relays@lists.torproject.org/>
 List-Help: <mailto:tor-relays-request@lists.torproject.org?subject=help>
 List-Owner: <mailto:tor-relays-owner@lists.torproject.org>
 List-Post: <mailto:tor-relays@lists.torproject.org>

Я открыл:

3 лайка