Erros Inexplicáveis de Email::Receiver::InvalidPost

Tenho algumas listas de e-mail espelhadas em Mailing Lists - Tor Project Forum

Recentemente, notamos que algumas mensagens não estavam sendo espelhadas da lista de e-mail Mailman3 para o fórum.

Os logs de rejeição de e-mail mostram que esses e-mails encontraram um erro Email::Receiver::InvalidPost.

A mensagem de erro registrada é uma das duas:

Lamentamos, mas sua mensagem de e-mail para [“tor-relays@lists.torproject.org”] (com o título [tor-relays] medições de largura de banda de autoridade e latência) não funcionou.

Motivo:

Acesso negado

Se você puder corrigir o problema, tente novamente.

ou:

Lamentamos, mas sua mensagem de e-mail para [“tor-relays@lists.torproject.org”] (com o título [tor-relays] Re: pontes webtunnel para o distribuidor do Telegram) não funcionou.

Motivo:

Algo deu errado. Talvez este tópico tenha sido fechado ou excluído enquanto você o visualizava?

Se você puder corrigir o problema, tente novamente.

Não consigo encontrar nada de errado com essas mensagens ao examinar os cabeçalhos, embora em alguns casos, o corpo extraído registrado contenha apenas o rodapé da lista de e-mail, ou em outro caso, seja um monte de caracteres sem sentido como se houvesse uma falha na decodificação.

Tentei reproduzir esse problema usando uma lista de e-mail de teste e uma categoria de teste, mas não obtive sucesso. Qualquer ajuda para depurar isso seria apreciada.

“aceitar e-mail de contas anônimas” está habilitado nas configurações de cada categoria, e você poderia enviar o log de e-mail do Discourse (levemente ocultado, se possível)?

1 curtida

Sim, posso confirmar que essa configuração está habilitada.

e você poderia enviar o log de e-mail do Discourse (levemente editado, se possível)

Isso é algo que preciso extrair do contêiner ou do host? Também processamos e-mails através do contêiner mail-receiver. Ou você quer os logs que são expostos na Interface Web (por exemplo, /admin/email-logs/rejected)?

Veio do Exchange?

Às vezes, o Microsoft Exchange envia lixo se estiver mal configurado para pensar que está falando com… Não tenho certeza - outro servidor Exchange? Algo mais dentro de sua própria infraestrutura?

Você pode ver o e-mail bruto do console do Discourse com, por exemplo:

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

Isso mostra o e-mail bruto que o Discourse recebeu. Por exemplo, este corpo de mensagem que acabei de extrair de nossa lista de rejeição de entrada é realmente lixo:

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

já que as partes não decodificam para texto válido.

2 curtidas

ambos seriam ótimos. Se você usar o PuTTy SSH, poderá extrair os logs do contêiner e poderá recortar a interface do usuário do Discourse. No entanto, você não pode pesquisar palavras na foto facilmente para ocultá-las😮‍💨

Consegui extrair dois e-mails com os cabeçalhos completos. Um MUA é o Apple Mail e o outro é o Claws Mail.

Ficarei feliz em encaminhá-los para o e-mail privado de alguém para depuração, para que evitemos colá-los em toda a Internet.

Acho que em ambos os casos é provável que o Discourse não esteja analisando o conteúdo do e-mail corretamente.

Para constar, este ainda é um problema. O Discourse descarta regularmente mensagens de listas de e-mail de vários remetentes com o erro Email::Receiver::InvalidPost, por motivos que não consigo descobrir.

Se você clicar no erro nos logs, ele mostra o motivo na razão de rejeição?

por exemplo:

Se você clicar no erro nos logs, ele mostra o motivo na razão de rejeição?

Essas mensagens vêm em dois sabores:

Lamentamos, mas sua mensagem de e-mail para [\"tor-relays@lists.torproject.org\"] (com o título [tor-relays] Re: abuse report from relays in family 7EAAC49A7840D33B62FA276429F3B03C92AA9327) não funcionou.

Motivo:

Algo deu errado. Talvez este tópico tenha sido fechado ou excluído enquanto você o estava visualizando?

Se você puder corrigir o problema, tente novamente.

Posso confirmar que nada disso (tópico fechado ou excluído) aconteceu nesses casos.

Outras vezes, o Motivo é simplesmente Acesso Negado.

Olá lavamind - desculpe ressuscitar um tópico antigo, mas eu queria verificar primeiro antes de aprofundarmos na depuração.

Você ainda está vendo as rejeições Email::Receiver::InvalidPost no espelhamento da lista de e-mail até agora (final de 2025 / início de 2026)?

Se sim, você poderia compartilhar um breve panorama de:

  • aproximadamente com que frequência isso acontece (por exemplo, diário / semanal, % das mensagens)
  • se a “Razão” do e-mail rejeitado ainda é principalmente “Acesso Negado” versus “tópico fechado/excluído”
  • se isso está afetando uma lista/categoria ou várias

Assim que confirmarmos que ainda está ocorrendo, poderemos prosseguir para coletar o conjunto mínimo de diagnósticos para uma única falha recente (Message-ID + o e-mail bruto armazenado correspondente, etc.).

Não precisa se desculpar, fico muito feliz que você esteja investigando isso.

Oi lavamind - desculpe por ressuscitar um tópico antigo, mas eu queria verificar antes de aprofundarmos mais na depuração.

Você ainda está vendo as rejeições Email::Receiver::InvalidPost na replicação da lista de e-mails no momento (final de 2025 / início de 2026)?

Sim, o problema ainda está ocorrendo.

aproximadamente com que frequência isso acontece (por exemplo, diariamente/semanalmente, % das mensagens)

A frequência é difícil de determinar exatamente, mas o problema afeta pelo menos várias mensagens por semana, uma estimativa aproximada talvez entre 5 a 10% das mensagens? Alguns remetentes parecem estar super-representados nos logs de erro, então pelo menos não parece totalmente aleatório.

se a “Razão” do e-mail rejeitado ainda é principalmente “Acesso Negado” versus “tópico fechado/excluído”

Ainda é uma mistura dos dois.

se está afetando uma lista/categoria ou várias

Está afetando principalmente a categoria tor-relays, mas esta lista recebe entrada regular de vários remetentes, ao contrário das outras listas que espelhamos, que recebem tráfego muito menor.

Assim que confirmarmos que ainda está ocorrendo, podemos prosseguir para coletar o conjunto mínimo de diagnósticos para uma falha recente (Message-ID + o e-mail bruto armazenado correspondente, etc.).

Poderíamos analisar este tópico recente. O arquivo do Mailman indica que recebeu 5 mensagens, mas o tópico espelhado do fórum tem apenas 3 postagens. Os logs de rejeição contêm 3 erros InvalidPost para este tópico (2 do mesmo remetente, estranhamente) e para todos eles a razão de rejeição mostrada é “Algo deu errado. Talvez este tópico tenha sido fechado ou excluído enquanto você olhava para ele?”

Obrigado, lavamind - esse é um dado muito útil, especialmente por termos um tópico concreto de “arquivo do Mailman mostra 5, tópico do fórum mostra 3” para nos ancorarmos.

Dado que você está vendo isso várias vezes por semana (cerca de 5-10% das mensagens) e que, para este incidente, o motivo da rejeição é consistentemente a variante enganosa de “tópico fechado/excluído”, o próximo passo ideal é capturar uma mensagem de ponta a ponta para vermos o que o Discourse pensou que estava fazendo.


Para um dos 3 e-mails rejeitados associados àquele tópico espelhado, você poderia obter o seguinte:

  1. Em /admin/email-logs/rejected, abra uma das linhas InvalidPost para aquele incidente e copie:

    • o Message-ID
    • a data/hora
    • o Para / De / Assunto (redigidos) mostrados na linha
    • o texto completo do motivo da rejeição (conforme exibido)
  2. No console do Rails (no contêiner do aplicativo Discourse), extraia o e-mail bruto que o Discourse armazenou:

@supermathie, IncomingEmail ainda é o local canônico para buscar o bruto, e há mais alguma coisa que você gostaria além dele para depurar o InvalidPost?

mid = "<cole aqui o Message-ID do log de e-mail rejeitado>"
ie  = IncomingEmail.find_by(message_id: mid)

puts ie&.raw
  1. Também extraia os atributos pareados do EmailLog para o mesmo Message-ID (isso geralmente revela se o Discourse o tratou como uma resposta ou um novo tópico, e quais IDs de tópico/categoria ele resolveu):
mid = "<o mesmo Message-ID acima>"

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 que este trio?

  • IncomingEmail.raw nos diz se o e-mail chegou malformado / codificado de forma estranha / apenas com rodapé, em oposição ao Discourse ter escolhido a parte MIME “errada”.
  • EmailLog nos diz o que o Discourse tentou (chave de resposta vs. roteamento de tópico, IDs de tópico/categoria resolvidos, etc.).
  • A linha da interface do e-mail rejeitado confirma que estamos olhando para o mesmo incidente e preserva o que os operadores veem.

Se a privacidade for uma preocupação, sinta-se à vontade para redigir endereços e qualquer texto do corpo da mensagem dentro do bruto, mas, por favor, mantenha:

  • Cabeçalhos MIME (Content-Type, limites, charset, Content-Transfer-Encoding)
  • A estrutura multipart (para que possamos ver quais partes existem)
  • O Message-ID e cabeçalhos de roteamento básicos (você pode redigir domínios, se necessário)

Assim que tivermos um Message-ID falho + IncomingEmail.raw + a fatia do EmailLog, poderemos dizer rapidamente se isso é:

  • uma incompatibilidade de chave de resposta/roteamento de tópico,
  • um caso extremo de permissões,
  • ou uma falha na análise de e-mail / seleção de parte MIME / decodificação.

Obrigado pelo guia detalhado!

Vamos nos concentrar em esta mensagem enviada ao tópico da lista de discussão.

Os cabeçalhos do incidente do log de postagem rejeitada mostram isto:

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

O texto completo do motivo da rejeição é este:

Lamentamos, mas sua mensagem de e-mail para ["tor-relays@lists.torproject.org"] (com o título [tor-relays] Re: Questions about running an exit relay) não funcionou.

Motivo:

Algo deu errado. Talvez este tópico tenha sido fechado ou excluído enquanto você o estava visualizando?

Se você puder corrigir o problema, tente novamente.

O registro em texto simples do e-mail enviado para o Discourse a partir do Mailman (IncomingEmail) está disponível aqui (não acredito que contenha dados que já não sejam públicos, mas de qualquer forma configurei esse link para expirar eventualmente).

Infelizmente, minhas tentativas de extrair o EmailLog não produziram nenhum resultado: parece que o Discourse não tem tal registro para essa mensagem.

Obrigado @lavamind - isto está excelente (ID da Mensagem + texto de rejeição + uma cópia do que o Discourse armazenou).

Além disso: minha culpa na solicitação de EmailLog - é muito plausível (e talvez esperado) que não haja nenhuma linha de EmailLog para uma rejeição de entrada como esta. EmailLog é primariamente para e-mails enviados, enquanto e-mails de entrada ficam em IncomingEmail (que você já buscou). @supermathie você pode confirmar que não estou enviando as pessoas pelo caminho errado aqui?

Dado que temos o IncomingEmail, você poderia colar os campos de metadados desse mesmo registro? Isso nos dará o contexto de “o que o Discourse tentou fazer?” que eu esperava obter do EmailLog.

No console do Rails:

# @supermathie verificação de sanidade: para depuração de Post Inválido de entrada, os metadados de IncomingEmail são a próxima coisa certa a coletar?
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: se você se sentir confortável, isto também é frequentemente útil
# (mostra o que o Discourse extraiu como corpo versus o que armazenou como bruto)
pp ie&.attributes&.slice("raw", "cooked")

(Se bruto/cozido estiverem muito grandes, sinta-se à vontade para omiti-los - você já compartilhou o bruto.)

Por que esses campos são importantes:

  • topic_id / post_id (se presentes) nos dizem se o Discourse resolveu isso como uma resposta/novo post e o que ele tinha como alvo.
  • user_id nos diz a qual usuário estagiário/real o remetente foi mapeado pelo Discourse (casos de permissão / “Acesso Negado”).
  • error é frequentemente mais específico do que o texto de rejeição genérico de “tópico fechado/excluído”.

Se esses atributos mostrarem que a resolução de topic_id/post_id aponta para o tópico espelho, então o próximo passo provável é descobrir por que o receptor decidiu que era inválido (corpo extraído vazio, decodificação MIME, incompatibilidade de permissões, incompatibilidade de chave de resposta, etc.). Se não mostrar nenhuma resolução de tópico/post, focamos nos cabeçalhos de roteamento / detecção de resposta.

E novamente - obrigado pelo link de colagem. Ter um único ID de Mensagem falho e concreto como este é exatamente o que precisávamos para parar de adivinhar.

Sim, isso está correto. E eu concordo - mostrará o que foi recebido, quais associações o Discourse conseguiu fazer e, com sorte, indicará o próximo passo.

1 curtida

Aqui estão os campos de metadados para o 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"}

Quanto aos conteúdos brutos/processados, apenas a propriedade raw contém o e-mail completo com cabeçalhos. A propriedade cooked não existe no objeto.

[quote=“lavamind, post:13, topic:377793”]O registro em texto simples do e-mail enviado para o Discourse pelo Mailman (IncomingEmail) está disponível aqui
[/quote]

Executar isso através de Email::Receiver.new(rawmessage).select_body retorna:

=> ["", "", 2]

Então, estou bastante confiante de que o que está acontecendo aqui é que o Discourse está selecionando incorretamente uma parte de texto simples vazia como o corpo da mensagem, provavelmente esta:

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


o que seria uma postagem inválida.

Precisaremos investigar um pouco isso e provavelmente usá-la como um caso de teste.

O e-mail tem a estrutura:

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

(sim, há três cópias do conteúdo real, conteúdo em branco e a assinatura PGP)

Essa primeira parte text/plain é adicionada pelo software da lista de e-mails e se parece com isto:

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

é isso que o Discourse (na verdade, o gem mail via .text_part) está escolhendo como conteúdo da mensagem:

> 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

e tratado como um corpo em branco com uma assinatura elidida.

Se não fosse por essa parte majoritariamente em branco adicionada pela lista de e-mails, o Discourse teria extraído o seguinte conteúdo para a postagem:

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

Que dados eles solicitaram?

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

Eles podem negar que você desligue o relay?
Se sim, você poderia operar um novo "sistema" em outro IP.

(parte elidida abaixo)

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

Eu realmente não consigo encontrar falhas no manuseio de e-mails do Discourse aqui - se eu fosse atribuir culpa, provavelmente começaria pelo software da lista de e-mails por efetivamente adicionar conteúdo em branco no início. Isso seria mais adequado no final, depois da mensagem real.

Teria funcionado com o Mail gem e também ficaria melhor nos clientes de e-mail - aqui está no Thunderbird como recebido originalmente:

e minha versão “corrigida” (test-fixed.eml.txt (14.3 KB))
com a assinatura da lista de e-mails no final em vez do topo:

Alcancei um assinante (humano) dessa lista e aqui está como o corpo da mensagem bruta se parece no MUA dele com alguns cabeçalhos 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==--

Não há duplicação, e as partes estão ordenadas corretamente. Eu esperaria que isso fosse mais parecido com o que o Mailman realmente envia aos assinantes da lista, caso contrário, se a maioria das pessoas estivesse recebendo mensagens com o rodapé no topo, talvez soubéssemos disso?

Estou me perguntando então se algo mais no pipeline de processamento pode estar mexendo com o corpo da mensagem. Nosso servidor Discourse primeiro processa o e-mail de entrada usando o Postfix, que é configurado para entregá-lo a um contêiner mail-receiver, que então o entrega ao contêiner Discourse.

Ah! Dado isso, voltei e investiguei novamente… e descobri que o problema é nosso, afinal.

A partir do e-mail bruto que você postou acima, acabei de descobrir que IncomingEmail.raw não armazena o e-mail bruto… nós o manipulamos primeiro com Email::Cleaner.

Isto parece ser culpa da gem mail do Ruby… ela reordena partes de uma mensagem de e-mail ao escrevê-la de volta:

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

o que causa o 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»
Detalhes da diferença

test.eml: mensagem bruta conforme fornecida
test-rubyparsed.eml: mensagem analisada pelo ruby e depois transformada de volta em uma string
test-pythonparsed.eml: mensagem analisada pelo python e depois transformada de volta em uma string

--- 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,15 @@
  --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 curtidas