Errores inexplicables de Email::Receiver::InvalidPost

Tenemos algunas listas de correo replicadas en Mailing Lists - Tor Project Forum

Recientemente notamos que algunos mensajes no se estaban replicando de la lista de correo Mailman3 al foro.

Los registros de rechazo de correo electrónico muestran que estos correos electrónicos encontraron un error Email::Receiver::InvalidPost.

El mensaje de error registrado es uno de los dos:

Lamentamos informarte que tu mensaje de correo electrónico a [“tor-relays@lists.torproject.org”] (con el asunto [tor-relays] mediciones de ancho de banda de autoridad y latencia) no funcionó.

Razón:

Acceso denegado

Si puedes corregir el problema, inténtalo de nuevo.

o:

Lamentamos informarte que tu mensaje de correo electrónico a [“tor-relays@lists.torproject.org”] (con el asunto [tor-relays] Re: puentes webtunnel para el distribuidor de telegramas) no funcionó.

Razón:

Algo salió mal. ¿Quizás este tema se cerró o eliminó mientras lo mirabas?

Si puedes corregir el problema, inténtalo de nuevo.

No encuentro nada malo en estos mensajes al revisar las cabeceras, aunque en algunos casos, el cuerpo extraído registrado solo contiene el pie de página de la lista de correo, o en otro caso, es un montón de caracteres sin sentido como si hubiera habido un error de decodificación.

He intentado reproducir este problema usando una lista de correo de prueba y una categoría de prueba, pero no tuve éxito. Cualquier ayuda para depurar esto sería apreciada.

¿Está habilitada la opción “aceptar correo electrónico de cuentas anónimas” en la configuración de cada categoría, y podría enviar el registro de correos electrónicos de Discourse (ligeramente redactado si es posible)?

1 me gusta

Sí, puedo confirmar que esta configuración está habilitada.

¿y podrías enviar el registro de correos electrónicos de Discourse (ligeramente redactado si es posible)?

¿Es algo que necesito extraer del contenedor o del host? También procesamos el correo a través del contenedor mail-receiver. ¿O quieres los registros que se exponen en la interfaz web (por ejemplo, /admin/email-logs/rejected)?

¿Vino de Exchange?

A veces, Microsoft Exchange envía basura si está mal configurado para pensar que está hablando con… No estoy seguro, ¿otro servidor Exchange? ¿Algo más dentro de su propia infraestructura?

Puedes ver el correo sin procesar desde la consola de Discourse con, por ejemplo:

mid = 'message-id from the log'
puts IncomingEmail.find_by(message_id: mid).raw

Esto muestra el correo sin procesar que Discourse recibió. Por ejemplo, el cuerpo de este mensaje que acabo de extraer de nuestra lista de rechazos entrantes es realmente basura:

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_=====--

ya que las partes no se decodifican a texto válido.

2 Me gusta

ambos estarían genial. Si usas PuTTy SSH puedes extraer los registros del contenedor y podrías extraer fragmentos de la interfaz de usuario de Discourse. Sin embargo, no puedes buscar palabras en la foto fácilmente para redactarlas :face_exhaling:

Pude extraer dos correos electrónicos con las cabeceras completas. Uno de los MUA es Apple Mail y el otro es Claws Mail.

Estaría encantado de reenviarlos al correo electrónico privado de alguien para depurar, así evitamos pegarlos por todo Internet.

Creo que en ambos casos es probable que Discourse no esté analizando el contenido del correo electrónico correctamente.

Para que conste, este sigue siendo un problema. Discourse descarta regularmente mensajes de listas de correo de varios remitentes con el error Email::Receiver::InvalidPost, por razones que no puedo descifrar.

Si haces clic en el error en los registros, ¿muestra el motivo en la razón del rebote?

por ejemplo:

Si haces clic en el error en los registros, ¿muestra el motivo en la razón de rebote?

Esos mensajes vienen en dos versiones:

Lo sentimos, pero su mensaje de correo electrónico a ["tor-relays@lists.torproject.org"] (titulado [tor-relays] Re: informe de abuso de relés en la familia 7EAAC49A7840D33B62FA276429F3B03C92AA9327) no funcionó.

Razón:

Algo salió mal. ¿Quizás este tema se cerró o se eliminó mientras lo mirabas?

Si puedes corregir el problema, inténtalo de nuevo.

Confirmo que no ha sucedido nada de eso (tema cerrado o eliminado) en estas instancias.

Otras veces, la Razón es simplemente Acceso Denegado.

Hola lavamind: lamento revivir un hilo antiguo, pero quería consultarte primero antes de profundizar en la depuración.

¿Todavía estás viendo los rechazos Email::Receiver::InvalidPost en el reflejo de la lista de correo en este momento (finales de 2025 / principios de 2026)?

Si es así, ¿podrías compartir una breve instantánea de:

  • aproximadamente con qué frecuencia ocurre (por ejemplo, diario/semanal, % de mensajes)
  • si la “Razón” del correo rechazado sigue siendo principalmente “Acceso Denegado” frente a “tema cerrado/eliminado”
  • si está afectando a una lista/categoría o a varias

Una vez que confirmemos que todavía está ocurriendo, podemos pasar a recopilar el conjunto mínimo de diagnósticos para un único fallo reciente (ID del mensaje + el correo sin procesar almacenado correspondiente, etc.).

No hay necesidad de disculparse, me alegra mucho que estés investigando esto.

Hola lavamind: lamento revivir un hilo antiguo, pero quería consultarte antes de que profundicemos más en la depuración.

¿Sigues viendo los rechazos de Email::Receiver::InvalidPost en el reflejo de la lista de correo a estas alturas (finales de 2025 / principios de 2026)?

Sí, el problema sigue ocurriendo.

aproximadamente con qué frecuencia ocurre (por ejemplo, diario/semanal, % de mensajes)

La frecuencia es difícil de precisar exactamente, pero el problema afecta al menos a varios mensajes por semana, ¿una estimación aproximada de entre el 5 y el 10% de los mensajes? Algunos remitentes parecen estar sobrerrepresentados en los registros de errores, por lo que al menos no parece totalmente aleatorio.

si la “Razón” del correo rechazado sigue siendo principalmente “Acceso Denegado” frente a “tema cerrado/eliminado”

Sigue siendo una mezcla de los dos.

si está afectando a una lista/categoría o a varias

Está afectando principalmente a la categoría tor-relays, pero esta lista recibe aportaciones periódicas de varios remitentes a diferencia de las otras listas que reflejamos, las cuales reciben mucho menos tráfico.

Una vez que confirmemos que sigue ocurriendo, podemos pasar a recopilar el conjunto mínimo de diagnósticos para un fallo reciente (ID del mensaje + el correo en bruto almacenado correspondiente, etc.).

Podríamos echar un vistazo a este hilo reciente. El archivo de Mailman indica que recibió 5 mensajes, pero el tema reflejado en el foro solo tiene 3 publicaciones. Los registros de rechazo contienen 3 errores de InvalidPost para este tema (2 del mismo remitente, curiosamente) y para todos ellos la razón de rechazo mostrada es “¿Algo ha salido mal. ¿Quizás este tema fue cerrado o eliminado mientras lo estabas mirando?”.

Gracias lavamind: ese es un dato realmente útil, especialmente al tener un hilo concreto de “el archivo de Mailman muestra 5, el tema del foro muestra 3” como punto de referencia.

Dado que estás viendo esto varias veces a la semana (aproximadamente el 5-10% de los mensajes) y que, para este incidente, el motivo del rebote es consistentemente la variante engañosa de “tema cerrado/eliminado”, el siguiente mejor paso es capturar un mensaje de principio a fin para que podamos ver lo que Discourse pensó que estaba haciendo.


Para uno de los 3 correos electrónicos rechazados asociados con ese tema espejo, ¿podrías obtener lo siguiente?

  1. Desde /admin/email-logs/rejected, abre una de las filas InvalidPost para ese incidente y copia:

    • el Message-ID
    • la fecha/hora
    • el Para / De / Asunto (redactado) que se muestra en la fila
    • el texto completo del motivo del rebote (tal como se muestra)
  2. Desde la consola de Rails (en el contenedor de la aplicación Discourse), extrae el correo electrónico sin procesar que almacenó Discourse:

@supermathie, ¿sigue siendo IncomingEmail el lugar canónico para obtener el contenido sin procesar, y hay algo más que te gustaría además de él para la depuración de InvalidPost?

mid = "<pega el Message-ID del registro de correo electrónico rechazado aquí>"
ie  = IncomingEmail.find_by(message_id: mid)

puts ie&.raw
3. También extrae los atributos de `EmailLog` emparejados para el mismo Message-ID (esto a menudo revela si Discourse lo trató como una respuesta o como un nuevo tema, y qué IDs de tema/categoría resolvió):
mid = "<mismo Message-ID que el anterior>"

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"
)

¿Por qué este trío?

  • IncomingEmail.raw nos dice si el correo llegó mal formado / codificado de forma extraña / solo con pie de página, en lugar de que Discourse eligiera la parte MIME “equivocada”.
  • EmailLog nos dice lo que intentó Discourse (nuevo tema vs. respuesta, IDs de tema/categoría resueltos, etc.).
  • La fila de la interfaz de usuario de correo electrónico rechazado confirma que estamos viendo el mismo incidente y conserva lo que ven los operadores.

Si la privacidad es una preocupación, siéntete libre de redactar las direcciones y cualquier texto del cuerpo del mensaje dentro de raw, pero por favor conserva:

  • Las cabeceras MIME (Content-Type, límites, charset, Content-Transfer-Encoding)
  • La estructura multipartes (para que podamos ver qué partes existen)
  • El Message-ID y las cabeceras básicas de enrutamiento (puedes redactar los dominios si es necesario)

Una vez que tengamos un Message-ID fallido + IncomingEmail.raw + la porción de EmailLog, deberíamos poder determinar rápidamente si esto se debe a:

  • una discrepancia de clave de respuesta/enrutamiento de tema,
  • un caso extremo de permisos,
  • o un fallo en el análisis del correo electrónico / selección de parte MIME / decodificación.

¡Gracias por el tutorial tan detallado!

Centrémonos en este mensaje enviado al tema de la lista de correo.

Los encabezados del incidente del registro de publicación rechazada muestran esto:

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

El texto completo de la razón del rechazo es este:

Lamentamos informarle que su mensaje de correo electrónico a ["tor-relays@lists.torproject.org"] (titulado [tor-relays] Re: Questions about running an exit relay) no funcionó.

Razón:

Algo ha salido mal. ¿Quizás este tema se cerró o eliminó mientras lo estaba viendo?

Si puede corregir el problema, intente de nuevo.

El registro en texto plano del correo electrónico enviado a Discourse desde Mailman (IncomingEmail) está disponible aquí (no creo que contenga datos que no sean ya públicos, pero de todos modos configuré ese enlace para que expire eventualmente).

Desafortunadamente, mis intentos de extraer el EmailLog no pudieron producir ningún resultado: parece que Discourse no tiene tal registro para ese mensaje.

Gracias @lavamind: esto es excelente (ID de mensaje + texto de rechazo + una copia de lo que Discourse almacenó).

Además: mis disculpas por la solicitud de EmailLog: es muy plausible (y quizás esperado) que no haya una fila de EmailLog para un rechazo entrante como este. EmailLog es principalmente para correo saliente, mientras que el correo entrante reside en IncomingEmail (que ya has extraído). @supermathie ¿puedes confirmar que no estoy enviando a la gente por el camino equivocado?

Dado que tenemos el IncomingEmail, ¿podrías pegar los campos de metadatos de ese mismo registro? Eso nos dará el contexto de “¿qué intentó hacer Discourse?” que esperaba obtener de EmailLog.

En la consola de Rails:

# @supermathie comprobación de cordura: para la depuración de InvalidPost entrante, ¿son los metadatos de IncomingEmail lo siguiente correcto a recopilar?
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"
)

# opcional: si te sientes cómodo, esto también suele ser útil
# (muestra lo que Discourse extrajo como cuerpo frente a lo que almacenó sin procesar)
pp ie&.attributes&.slice("raw", "cooked")

(Si raw/cooked son enormes, no dudes en omitirlos; ya has compartido el raw).

Por qué estos campos son importantes:

  • topic_id / post_id (si están presentes) nos dice si Discourse resolvió esto como una respuesta/publicación nueva y qué tuvo como objetivo.
  • user_id nos dice a qué usuario provisional/real mapeó Discourse al remitente (casos de permisos / “Acceso Denegado”).
  • error es a menudo más específico que el texto de rebote genérico de “tema cerrado/eliminado”.

Si esos atributos muestran que la resolución de topic_id/post_id apunta al tema espejo, entonces el siguiente paso probable es averiguar por qué el receptor decidió que no era válido (cuerpo extraído vacío, decodificación MIME, falta de coincidencia de permisos, falta de coincidencia de clave de respuesta, etc.). Si no muestra ninguna resolución de tema/publicación, nos centramos en las cabeceras de enrutamiento / detección de respuesta.

Y de nuevo: gracias por el enlace de pegado. Tener un único ID de mensaje fallido y concreto como este es exactamente lo que necesitábamos para dejar de adivinar.

Sí, esto es correcto. Y estoy de acuerdo: mostrará lo que se recibió, qué asociaciones pudo hacer Discourse y, con suerte, indicará el siguiente paso.

1 me gusta

Aquí están los campos de metadatos para el 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"}

En cuanto a los contenidos sin procesar/cocidos, solo la propiedad raw contiene el correo electrónico completo con encabezados. La propiedad cooked no existe en el objeto.

[quote=“lavamind, post:13, topic:377793”]El registro en texto plano del correo electrónico enviado a Discourse desde Mailman (IncomingEmail) está disponible aquí
[/quote]

Al ejecutar eso a través de Email::Receiver.new(rawmessage).select_body devuelve:

=> ["", "", 2]

Así que estoy bastante seguro de que lo que está sucediendo aquí es que Discourse está seleccionando incorrectamente una porción de texto plano vacía como el cuerpo del mensaje, probablemente esta:

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


lo que sería una publicación no válida.

Necesitaremos investigar un poco sobre esto y probablemente usarlo como caso de prueba.

El correo tiene la estructura:

* #<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

(sí, hay tres copias del contenido real, contenido vacío y la firma PGP)

Esa primera parte text/plain la añade el software de la lista de correo y se ve así:

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

eso es lo que Discourse (realmente, el gem mail a través de .text_part) está eligiendo como contenido del mensaje:

> 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

y se trata como un cuerpo en blanco con una firma elidida.

Si no fuera por esta parte mayormente en blanco añadida por la lista de correo, Discourse habría extraído el siguiente contenido para la publicación:

> 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...

¿Qué datos solicitaron?

> 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.

¿Pueden negarte apagar el relay?
Si es así, podrías operar un nuevo "sistema" en otra IP.

(parte elidida más abajo)

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

Realmente no puedo encontrar fallos en el manejo del correo de Discourse; si tuviera que repartir culpas, probablemente empezaría por el software de la lista de correo por añadir efectivamente contenido en blanco al principio. Eso estaría mejor situado al final, después del mensaje real.

Habría funcionado con el gem Mail y también se vería mejor en los clientes de correo; aquí está en Thunderbird tal como se recibió originalmente:

y mi versión “corregida” (test-fixed.eml.txt (14.3 KB))
con la firma de la lista de correo al final en lugar de al principio:

He contactado a un suscriptor (humano) de esa lista y así es como se ve el cuerpo del mensaje sin procesar en su MUA con algunos encabezados filtrados:

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...

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.

--=20
kind regards
Marco

Send spam to 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==--

No hay duplicación y las partes están ordenadas correctamente. Esperaría que esto se parezca más a lo que Mailman realmente envía a los suscriptores de la lista, de lo contrario, si la mayoría de las personas recibieran mensajes con el pie de página arriba, ¿quizás nos enteraríamos?

Entonces me pregunto si algo más en el pipeline de procesamiento podría estar alterando el cuerpo del mensaje. Nuestro servidor Discourse primero procesa el correo electrónico entrante usando Postfix, que está configurado para pasarlo a un contenedor mail-receiver, que luego lo pasa al contenedor de Discourse.

¡Oh! Dado esto, he vuelto a investigar… y resulta que es nuestro problema después de todo.

A partir del correo electrónico sin procesar que publicaste arriba, acabo de descubrir que IncomingEmail.raw no almacena el correo electrónico sin procesar… lo manipulamos primero con Email::Cleaner.

Parece ser culpa de la gema mail de Ruby… reordena partes de un mensaje de correo al escribirlo de nuevo:

[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>>
]

lo que causa el problema:

[38] pry(main)> puts Email::Receiver.new(m).select_body[0];
=> 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.

[39] pry(main)> puts Email::Receiver.new(Mail.new(m).to_s).select_body[0];
«no output»
Detalles de la diferencia

test.eml: mensaje sin procesar tal como se proporcionó
test-rubyparsed.eml: mensaje analizado por ruby y luego convertido de nuevo a una cadena
test-pythonparsed.eml: mensaje analizado por python y luego convertido de nuevo a una cadena

--- 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,14 +69,15 @@
  --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 Me gusta