Sur discuss python org, nous discutons de la partie e-mail de Discourse. Le principal grief est le manque de filtres. J’ai un peu fouillé dans les en-têtes et il semble que :
l’en-tête Message-ID soit au moins unique
les en-têtes Reply-To et References ne font pas référence aux Message-ID d’autres messages, encore moins à l’ID du message auquel ils répondent
ils font référence à un ID de message fictif basé sur le numéro du sujet
Cela signifie que les personnes utilisant l’e-mail voient (a) des discussions totalement plates et non filetées et (b) le message racine est apparemment manquant, car les en-têtes In-Reply-To et References font référence à un ID de message qui n’apparaît jamais dans aucun message.
C’est mal, et en violation de la RFC 5322. Et cela rend l’expérience de l’e-mail bien moins bonne qu’elle ne pourrait facilement l’être.
À titre d’exemple, il y a un fil de discussion là-bas dont le premier message a ces en-têtes :
Encore une fois, un Message-ID correct, mais des In-Reply-To et References complètement absurdes.
Cela devrait être facile à corriger. Le premier message ne devrait avoir ni en-tête In-Reply-To ni References. Le deuxième message devrait avoir le Message-ID du premier message dans les en-têtes In-Reply-To et References.
Veuillez consulter la section 3.6.4 de la RFC 5322 pour plus de détails :
En l’état actuel des choses, les utilisateurs d’e-mail voient des discussions plates et non structurées. Avec ces corrections, ils peuvent avoir un affichage threadé sensé et facile à suivre.
Au cas où cela intéresserait quelqu’un, les archives de la discussion à laquelle Cameron fait référence se trouvent sur \u003chttps://mail.python.org/archives/list/python-dev@python.org/message/VHFLDK43DSSLHACT67X4QA3UZU73WYYJ/\u003e.
Je jette juste un coup d’œil à la différence entre HEAD et ce correctif.
Il me semble que current définit toujours References, même s’il n’y a pas d’antécédent - topic_canonical_reference_id est utilisé comme solution de repli. Je pense toujours que c’est faux, car il n’y a pas de message e-mail avec cet identifiant.
In-Reply-To est un peu plus correct, en ce sens qu’il n’est défini que si post.post_number!=1, mais il utilise toujours topic_canonical_reference_id comme solution de repli :
la solution de repli devrait être le Message-ID du post #1 s’il n’y a pas de referenced_post_message_ids, et pastopic_canonical_reference_id
quelque chose dans le code de receipt-of-reply-emails doit supprimer l’en-tête In-Reply-To des messages de réponse, car ils auraient correctement rempli le tableau referenced_post_message_ids (« liste » ? Je suis nouveau en Ruby)
Cameron, merci d’avoir ouvert ce sujet à la discussion et d’avoir fourni beaucoup de détails dans vos publications. Je suis responsable de cette boîte de Pandore, issue de ces deux commits :
Nous sommes conscients de certains problèmes liés au threading dans les clients de messagerie tels que Thunderbird depuis un certain temps, mais cela ne représentait pas un grand nombre de consommateurs de threading par e-mail à partir de Discourse, donc cela a été repoussé. Mais maintenant que cela apparaît, nous devons passer du temps à réexaminer le problème et à travailler sur une solution.
Il est intéressant de noter que nous avons ajouté cet en-tête References au premier e-mail envoyé et à tous les suivants à l’époque, car cela permet au threading de fonctionner correctement dans Gmail, mais je suis d’accord que ce n’est pas idéal et que cela cause probablement les problèmes de threading, ainsi que le fait de ne pas utiliser le Message-ID original dans les en-têtes In-Reply-To et References des e-mails suivants.
Merci de votre patience pendant que j’examine les anciennes discussions et le code et que je travaille sur ce problème. En attendant, êtes-vous au courant d’autres clients de messagerie utilisés et qui rencontrent des problèmes ? Par exemple, je sais que c’est un problème dans Thunderbird, mais qu’en est-il des autres ? Merci.
Nous sommes désolés, mais votre message électronique à
["incoming+8349bd9eb1f2b582df4f32dbe85c3363@meta.discoursemail.com"]
(intitulé Re: [Discourse Meta] [bug] Les messages électroniques de Discourse sont
incorrectement classés par fil de discussion) n'a pas fonctionné.
Raison :
Désolé, les nouveaux utilisateurs ne peuvent mettre que 2 liens dans un message.
Si vous pouvez corriger le problème, veuillez réessayer.
Je vais la mettre sur le forum où je pourrai la rattraper et la réviser…
Cameron, merci d’avoir ouvert ce sujet à la discussion et d’avoir fourni
beaucoup de détails dans vos publications. Je suis responsable de cette boîte de Pandore,
à partir de ces deux commits :
3b13f1146b2a406238c50d6b45bc9aa721094f46
Cela semble correct. Est-ce que cela enregistre cet ID avec l’enregistrement de la base de données afin que les réponses entrantes puissent être liées au message de forum précédent ?
Voulez-vous également que je vérifie si le suffixe est syntaxiquement légal pour le RFC5322, en termes de caractères autorisés ?
82cb67e67b83c444f068fd6b3006d8396803454f
Ce second commit semble aborder un autre problème que nous avons rencontré : si un message provient d’un e-mail, le message-id sortant envoyé aux utilisateurs d’e-mail n’est pas le message-id du message source de l’auteur. Cela se traduit par deux messages distincts du point de vue d’un client de messagerie, et cela casse probablement les réponses faites à l’original par opposition à la copie envoyée par le forum. Par exemple :
À : le forum
CC : un des participants
Le participant recevra (eh bien, peut-être) une copie du forum et une copie directe de l’auteur, et ce seront des messages distincts de leur côté car ils auront des message-ids différents.
J’allais faire un second rapport de bug sur ce problème après avoir résolu le problème des en-têtes in-reply-to et references, qui est beaucoup plus important.
Nous sommes conscients de certains problèmes liés au chaînage depuis un certain temps dans les clients de messagerie tels que Thunderbird, mais cela ne représentait pas un grand nombre de consommateurs de chaînage d’e-mails de Discourse, donc cela a été repoussé, mais maintenant que cela apparaît, nous devons passer du temps à réexaminer le problème et à travailler sur une solution.
Je et plusieurs autres utilisons mutt. Je suis heureux de faire tout ce qui est nécessaire pour aider au débogage et à la revue de code. J’ai également été administrateur système de messagerie pendant des lustres dans mes vies antérieures.
[quote=“Cameron Simpson, post:1, topic:233499,
username:cameron-simpson”]
C’est le premier message. Il ne devrait pas avoir d’en-tête References, car il n’y a pas de message quelque part avec cet id.
[/quote]
Fait intéressant, nous avons ajouté cet en-tête References au premier e-mail envoyé et à tous les suivants depuis lors, car cela permet au chaînage de fonctionner correctement dans Gmail,
Je pense qu’un en-tête References correct (absent dans le premier message, comme in-reply-to dans les réponses) devrait également fonctionner. Mais GMail a une relation plutôt lâche avec les normes de messagerie parfois. J’ai un accord gmail ; je peux aussi faire du débogage là-bas. Et en principe, nous pouvons utiliser cette discussion même comme banc d’essai, peut-être.
mais je suis d’accord que ce n’est pas idéal et que cela cause probablement les problèmes de chaînage
ainsi que le fait de ne pas utiliser le Message-ID original dans les en-têtes In-Reply-To et References des e-mails suivants.
Merci de votre patience pendant que j’examine les anciennes discussions et le code et que je travaille sur ce problème.
Pas de souci.
En attendant, êtes-vous au courant d’autres clients de messagerie qui sont utilisés et qui rencontrent des problèmes ? Par exemple, je sais que c’est un problème dans Thunderbird, mais qu’en est-il des autres ? Merci.
Certainement mutt. Au moins avec mutt, il est très facile de voir les en-têtes et aussi de voir la chaîne de l’arbre de réponses, qui est souvent obscurcie dans d’autres clients.
Le chaînage de messages est entièrement défini par les en-têtes Message-ID et In-Reply-To. L’en-tête References a commencé avec USENET pour les suivis, et prenait en charge (là-bas) plusieurs message-ids ; le In-Reply-To n’en prend en charge qu’un seul. Il semble que References soit maintenant également présent dans RFC5322, et je vais vérifier sa sémantique.
Je suis juste en train de rassembler mes idées dans un grand article à ce sujet pour plus tard aujourd’hui, merci pour les informations supplémentaires jusqu’à présent !
D’accord, c’est assez énorme, merci de votre patience. Tout d’abord, merci pour une autre réponse détaillée et pour l’offre de débogage/révision, c’est vraiment utile J’ai en fait examiné cela ce matin et, étonnamment, le chaînage dans une vue unifiée fonctionne dans Thunderbird dans la plupart des cas, et je pense que l’en-tête References pointant constamment vers l’OP y contribue (par exemple, le sujet Reference dans cette chaîne qui est toujours présent est \u003ctopic/53@discoursehosted.martin-brennan.com\u003e.\n\n
\n\nLe cas où le chaînage ne fonctionne pas comme prévu est le suivant :\n\n1. Un message est créé dans Discourse et un e-mail est envoyé à ceux qui suivent le sujet puis\n2. Quelqu’un d’autre répond à ce message et un e-mail est envoyé à ceux qui suivent le sujet\n\nDans le cas du second e-mail, il reçoit un en-tête In-Reply-To et References incorrect car il en génère un sur cette ligne discourse/lib/email/sender.rb at 98bacbd2c6b9fe57167cd32af5eb4839b4a5d1f6 · discourse/discourse · GitHub plutôt que d’utiliser un en-tête existant. Il devrait utiliser le Message-ID de l’e-mail qui a été envoyé en premier. Dans la capture d’écran, c’est là que les messages suivant ce modèle devraient être placés :\n\n
\n\n\n\n[quote="Cameron Simpson, post:8, topic:233499, username:cameron-simpson"]\nCela semble correct. Cela enregistre-t-il cet identifiant avec l’enregistrement de la base de données afin que les réponses entrantes puissent être liées au message de forum précédent ?\n[/quote]\n\nLa réponse est – cela dépend. Si un message est créé dans Discourse à partir d’un e-mail entrant, comme celui-ci de votre part, nous utilisons le Message-ID entrant d’origine de ce message lorsque quelqu’un y répond pour les en-têtes In-Reply-To et References conformément à :\n\ndiscourse/lib/email/sender.rb at 98bacbd2c6b9fe57167cd32af5eb4839b4a5d1f6 · discourse/discourse · GitHub, nous utilisons simplement la référence de l’OP du sujet et générons une nouvelle référence, ce qui est évidemment ce qui cause tous les problèmes. Dans tous les cas, nous générons un nouveau Message-ID à chaque fois qu’un e-mail sortant est envoyé, ce qui semble correct et à la hauteur des autres clients de messagerie.\n\n[quote="Cameron Simpson, post:8, topic:233499, username:cameron-simpson"]\nCe deuxième commit semble résoudre un autre problème que nous avons rencontré : si un\nmessage provient d’un e-mail, le message sortant envoyé aux utilisateurs par e-mail n’est pas le message-id du message source de l’auteur. Cela entraîne\ndeux messages différents du point de vue d’un client de messagerie, et\ncasse probablement les réponses faites à l’original par opposition à la\ncopie envoyée par le forum.\n[/quote]\n\nJe pense comprendre ce que vous voulez dire, est-ce que cela se passe comme suit :\n\n1. cameron envoie un e-mail à Discourse depuis mutt, qui reçoit Message-ID: 74398756983476983@mail.com\n2. Discourse crée un message et stocke le Message-ID associé au message avec un enregistrement IncomingEmail\n3. johndoe suit le sujet, il reçoit donc un e-mail de Discourse avec un Message-ID: topic/222/44@discourse.com et aucune référence à l’Message-ID original : 74398756983476983@mail.com\n\nEst-ce que cela vous semble correct, que nous devrions simplement “transmettre” ce Message-ID à ceux qui suivent le sujet au lieu de générer le nôtre puisqu’il est déjà unique ? Que se passe-t-il alors dans le client de messagerie de johndoe si\ncameron l’a également mis en copie sur cet e-mail sortant original ? Cela semble être un problème distinct, il serait donc bon d’ouvrir un autre sujet de bug à ce sujet.\n\n[quote="Cameron Simpson, post:8, topic:233499, username:cameron-simpson"]\nPlusieurs d’entre nous utilisent mutt.\n[/quote]\n\nJe vais configurer un client mutt localement pour voir ce que vous voyez également, je n’ai jamais testé cette fonctionnalité dans un client textuel (uniquement Gmail et Thunderbird) donc je suis impatient de voir à quoi cela ressemble de toute façon.\n\n-----\n\nMa réflexion pour résoudre ces problèmes ce matin a été de supprimer les suffixes générés aléatoirement lorsque nous envoyons des en-têtes Message-ID dans les e-mails et de passer plutôt à un schéma où nous utilisons l’user_id de l’utilisateur expéditeur et du destinataire. L’avantage est qu’il n’est pas nécessaire de stocker le Message-ID n’importe où (sauf lorsqu’un e-mail entrant crée un message) et donc les en-têtes References et In-Reply-To seront toujours cohérents. Laissez-moi vous donner un exemple. Supposons que nous ayons ces utilisateurs :\n\n* martin - user_id 25\n* cameron - user_id 44\n* sam - user_id 78\n* bob - user_id 999\n\nEt puis nous avons ce sujet, topic_id 233499, avec des messages commençant par post_id 100 comme OP. Le format deviendrait topic/#{topic_id}/#{post_id}.s#{sender_user_id}r#{receiver_user_id}. L’ordre des opérations ressemblerait à ceci :\n\n1. martin crée l’OP\n * cameron reçoit un e-mail avec ces en-têtes :\n * Message-ID: topic/233499.s25r44@meta.discourse.org\n * References: topic/233499@meta.discourse.org\n * sam reçoit un e-mail avec ces en-têtes :\n * Message-ID: topic/233499.s25r78@meta.discourse.org\n * References: topic/233499@meta.discourse.org\n\n2. cameron répond par e-mail\n\n * discourse reçoit un e-mail avec ces en-têtes depuis mutt :\n * Message-ID: 43585349859734@test.com\n * References: topic/233499@meta.discourse.org topic/233499.s25r44@meta.discourse.org\n * In-Reply-To: topic/233499.s25r44@meta.discourse.org\n\n3. discourse (en tant que cameron, de l’e-mail ci-dessus) crée le message 101\n\n * sam reçoit un e-mail de Discourse avec ces en-têtes :\n * Message-ID: topic/233499/101.s44r78@meta.discourse.org\n * References: 43585349859734@test.com topic/233499@meta.discourse.org\n * In-Reply-To: 43585349859734@test.com\n\n2. sam répond par e-mail à cameron\n\n * discourse reçoit un e-mail avec ces en-têtes depuis gmail :\n * Message-ID: 5346564746574@gmail.com\n * References: topic/233499/101.s44r78@meta.discourse.org topic/233499@meta.discourse.org\n * In-Reply-To: topic/233499/101.s44r78@meta.discourse.org\n\n4. discourse (en tant que sam, de l’e-mail ci-dessus) crée le message 102\n\n * cameron reçoit un e-mail de Discourse avec ces en-têtes :\n * Message-ID: topic/233499/102.s78r44@meta.discourse.org\n * References: 5346564746574@gmail.com topic/233499@meta.discourse.org\n * In-Reply-To: 5346564746574@gmail.com\n\n5. bob crée le message 103 dans le sujet, pas en réponse à quelqu’un (notez que les References incluent ici le Message-ID envoyé aux deux utilisateurs pour l’e-mail OP)\n * cameron reçoit un e-mail avec ces en-têtes :\n * Message-ID: topic/233499/103.s999r44@meta.discourse.org\n * References: topic/233500@meta.discourse.org topic/23499.s25r44@meta.discourse.org\n * sam reçoit un e-mail avec ces en-têtes :\n * Message-ID: topic/233499/103.s999r78@meta.discourse.org\n * References: topic/233499@meta.discourse.org topic/23499.s25r78@meta.discourse.org\n\n6. cameron répond par e-mail\n\n * discourse reçoit un e-mail avec ces en-têtes depuis mutt :\n * Message-ID: 6759850728742572@test.com\n * References: topic/233499@meta.discourse.org topic/233499/103.s999r44@meta.discourse.org\n * In-Reply-To: topic/233499/103.s999r44@meta.discourse.org\n\nBoîte de réception de cameron\n\n* martin - OP du sujet\n * ENVOYÉ -\u003e à : discourse, RE : OP du sujet\n * sam - réponse au deuxième message\n * bob - réponse dans le sujet, pas à un message particulier\n * ENVOYÉ -\u003e à : discourse, RE : message de bob\n\nBoîte de réception de sam\n\n* martin - OP du sujet\n * cameron - deuxième message\n * ENVOYÉ -\u003e à : discourse, RE : deuxième message\n * bob - réponse dans le sujet, pas à un message particulier\n\nJe pense que c’est correct, pouvez-vous juste examiner ce que j’ai écrit dans ces en-têtes et vérifier si c’est ce que vous attendriez de ce scénario ? La seule chose dont je ne suis pas tout à fait sûr, c’est si j’ai couvert toutes les References, et bien sûr, je testerais cela sur un ensemble d’e-mails en direct dans une branche de développement avant de le déployer. Je n’ai pas encore testé quoi que ce soit dans mutt non plus.\n\n-----\n\nEn aparté, j’ai également examiné ce que GitHub fait avec ses e-mails de notification, et j’ai remarqué qu’ils font quelque chose de similaire où ils ont une Reference omniprésente (discourse/discourse/pull/252@github.com) qui est utilisée dans tous les e-mails liés à ce “sujet”, qui dans ce cas est une pull request GitHub :\n\n\nReferences: \u003cdiscourse/discourse/pull/252@github.com\u003e \u003cdiscourse/discourse/pull/252/issue_event/7042100517@github.com\u003e\nIn-Reply-To: \u003cdiscourse/discourse/pull/252/issue_event/7042100517@github.com\u003e\n
By Martin Brennan via Discourse Meta at 22Jul2022 06:34:
Okay this is kind of huge, please bear with me. First, thanks for
another detailed reply and the offer of debugging / review, it is
really helpful I’ve actually been looking into this this morning
and, surprisingly, the threading in a unified view works in Thunderbird
for most cases, and I think the References header consistently
pointing to the OP helps with that (for example the topic Reference
in this chain which is always present is <topic/53@discoursehosted.martin-brennan.com>.
I’ve just reread RFC5322 section 3.6.4 closely. It has moved on from
earlier versions (822 and 2822), and has merged the email In-Reply-To
headers, USENET References headers and modern
reply-citing-more-that-one previous messages.
The short summary:
The Message-ID is a single persisent identifier for a message
The In-Reply-To contains all the message-ids of which this message
is a direct reply, so if I reply to a pair of messages it will have
those 2 message-ids
The References is a reply chain of antecedant message-ids from the
OP to the preceeding message. So indeed it should always start with
the OP message-id.
So for a discussions like this, pretending that labels are message-ids:
It is also leagel to include “reply1 reply2” in the references (the
other chain to reply5) but the RFC explicitly recommends against that
becaause some clients expect the references to be a single linear chain
of replies, not some flattened digraph.
So my recommendation for constructing the references is to use the
references of the “primary” antecedant message with the primary
antecedant message’s message-id appended. That way you always get a
linear chain in the correct order.
Interestingly there seems to be some threading there.
But notice: the top post has a little “is a reply” arrow. Even though it
is post 1. I expect that is because of the “topic” references entry,
which make TB think there was a earlier message (which of course there
was not).
In mutt-land we see almost no threading at all:
23Jul2022 06:24 Olha via Discus - ┌>[Py] [Users] I need an advise discuss-users 5.7K
22Jul2022 17:12 Paul Jurczak vi - ├>[Py] [Users] I need an advise discuss-users 5.5K
22Jul2022 13:21 Rob via Discuss - ├>[Py] [Users] I need an advise discuss-users 6.8K
22Jul2022 12:53 vasi-h via Disc - ├>[Py] [Users] I need an advise discuss-users 5.5K
22Jul2022 11:38 Cameron Simpson - ├>[Py] [Users] I need an advise discuss-users 14K
22Jul2022 10:27 Rob via Discuss - ├>[Py] [Users] I need an advise discuss-users 6.6K
22Jul2022 06:14 vasi-h via Disc r ┴>[Py] [Users] I need an advise discuss-users 6.5K
which is because every message’s In-Reply-To points directly at the
fictitious “topic” message-id. Mutt probably ignores the References
because it is a mail reader, and References originates in USENET news.
Maybe Thunderbird is using the references or augumenting the in-reply-to
with references information.
You only need to consult one of In=-Reply-To or References to do
threading; the former comes from email and the latter from USENET.
You’re supporting both (which is great!) so we need to make them
consistent.
(Aside: there’s also discussion about USENET mirroring, because several
python people consume the lists via a USENET interface. Again, a
separate topic.)
[…]
[quote=“Cameron Simpson, post:8, topic:233499,
username:cameron-simpson”]
This looks fine. Does it save this id with the db record so that inbound
replies can be tied to the antecedant forum message?
[/quote]
The answer is – it depends. If a post is created in Discourse from an inbound email, such as this one of yours, we use that post’s original inbound Message-ID when someone replies to it for the In-Reply-To and References headers as per:
Otherwise we are just using the topic OP reference and just generating a new reference, which obviously is what is causing all the issues. In all cases we generate a new Message-ID every time an outbound email is sent, which seems correct and on par with other mail clients.
Alas, not quite. If you’re the origin of the message (i.e. authored in
Discourse), generating the message-id is fine. If there’s no message-id
(illegal) generating one is standard practice (usually by MTAs). But if
you’re passing a message on (authored in email), the existing message-id
should be preserved.
To my mind you need to be doing 3 things:
having a stable message-id and not replacing the message-id from an
inbound message
generating correct In-Reply-To, which is easily computed from the
immediate antecedant message(s) i.e. antecedant(s)-Message-ID
generating correct References, which is easily computed as
antecedant-References + antecedant-Message-ID
For point 1, looking at the code you cite, you probably want the email
message id to be (Pythonish syntax, sorry):
def message_id(post):
return post.incoming_email.message_id or discourse_message_id(post)
i.e. to be the post’s email message-id if it originated from email,
otherwise the Discourse message-id using something like the algorithm
you outline later in this message: anything (a) stable and (b)
syntacticly valid.
Then computing the In-Reply-To and References fields is simple
mechanical stuff as in points 2 and 3.
I think I see what you mean, does it go like this:
cameron sends email to Discourse from mutt which gets Message-ID: 74398756983476983@mail.com
Discourse creates a post and stores the Message-ID with against the post with an IncomingEmail record
Correct.
johndoe is watching the topic, so they get sent an email from Discourse with a Message-ID: topic/222/44@discourse.com and no reference to the original Message-ID: 74398756983476983@mail.com
No. You really want to pass through IncomingEmail.message_id as the Message-ID in the email to johndoe. It’s the same message.
Does that sound correct, that we should just “pass on” that Message-ID to those watching the topic instead of generating our own since it’s already unique? What then happens in johndoe’s mail client if
cameron also CC’d him on that original outbound message? This does sound like a separate issue so it would be good to open another bug topic for it.
By passing it on, the original message (cameron->cc:johndoe) and the
Discourse forwarded message (cameron->Discourse->johndoe) have the same
message-id and the same message contents. The receiving mail system
stores both. The mail reader sees both, and either presents both or
keeps just one (this is a policy decision of the mail reader - keeping
just one is common). Because they’re the same message, in general it
does not matter which is kept.
If we ignored discourse and considered a message which was
a copy of the message via the list and also via direct email. They’re
the same message, with the same message-id.
I will set up a mutt client locally to see what you are also seeing, I have never tested this functionality in a text-based client (only Gmail and Thunderbird) so I am keen to see how it looks anyway.
Happy to help with settings. For threaded view you need to set the
sorting to threadeed. Mutt is very configurable.
My line of thinking to address these issues this morning was to dispose
with the randomly generated suffixes generated when we send Message-ID headers in emails and instead change to a scheme where we
use the user_id of both the sending and receiving user. The benefit
of this is that there is no need to store the Message-ID anywhere
(apart from when an inbound email creates a post) and so References
and In-Reply-To headers will always be consistent.
Yes, that is much better. Noting that the inbound email message-id
should override the Discourse derived message-id for the outbound email.
(Most mail systems use random strings because there’s no surrounding
context such as the discourse topic message structure - messages are
considered alone; but the only real requirement is persistent
uniqueness.)
Let me give an example. Say we have these users:
martin - user_id 25
cameron - user_id 44
sam - user_id 78
bob - user_id 999
And then we have this topic, topic_id 233499, with posts starting from post_id 100 as the OP. The format would become topic/#{topic_id}/#{post_id}.s#{sender_user_id}r#{receiver_user_id}.
There should not be a References header in the OP. It isn’t
needed for threading and effectively pretends there’s some “post 0”
which doesn’t exist. It meeans every OP (a) looks like a reply, which it
is not and (b) looks like the thing to which it is a reply is missing
from the reader’s mailbox.
This makes different message-ids for each outbound copy of the OP.
That’s bad. They need to be the same. Supposing sam CCs cameron
directly in a reply. The In-Reply-To will cite a mesage-id cameron
has never received.
You can just drop the sender_user_id and receiver_user_id from the
message-id field and get a single unique id which every receiver sees.
The uniqueness constraint is the post itself, not the individual
email-level “message” object.
Re the References, the OP should not have one. TB and everything else
will be fine. If they’re threading using References instead of In-Reply-To, the References in the reply messages are enough.
Here’s the start of a mailing list discussion thread in Mutt:
16Jul2022 01:09 Rob Boehne - │├>[Python-Dev] Re: [SPAM] Re: Swit python-dev 9.2K
16Jul2022 01:33 Peter Wang - │├> python-dev 3.0K
16Jul2022 00:24 Skip Montanaro - ├>[Python-Dev] Re: Switching to Dis python-dev 4.2K
16Jul2022 04:49 Erlend Egeberg - ├>[Python-Dev] Re: Switching to Dis python-dev 10K
16Jul2022 04:20 Mariatta - ├>[Python-Dev] Re: Switching to Dis python-dev 10K
15Jul2022 21:18 Petr Viktorin - [Python-Dev] Switching to Discourse python-dev 4.2K
Ignore that I sort my email newest-on-top. See that there’s no arrow on
the initial post (at the bottom). That messgae has no References and
no In-Reply-To. All the others have In-Reply-To (and possibly References, but this is an email mailing list so not necessarily; as I
mentioned before they’re complimentary.)
If I repeat my Discourse example from earlier:
23Jul2022 06:24 Olha via Discus - ┌>[Py] [Users] I need an advise discuss-users 5.7K
22Jul2022 17:12 Paul Jurczak vi - ├>[Py] [Users] I need an advise discuss-users 5.5K
22Jul2022 13:21 Rob via Discuss - ├>[Py] [Users] I need an advise discuss-users 6.8K
22Jul2022 12:53 vasi-h via Disc - ├>[Py] [Users] I need an advise discuss-users 5.5K
22Jul2022 11:38 Cameron Simpson - ├>[Py] [Users] I need an advise discuss-users 14K
22Jul2022 10:27 Rob via Discuss - ├>[Py] [Users] I need an advise discuss-users 6.6K
22Jul2022 06:14 vasi-h via Disc r ┴>[Py] [Users] I need an advise discuss-users 6.5K
See they all have a leading arrow? That is because the mail client
believes they are all replies to a common (and missing) root message,
which is because of the “topic” message-id in the References header.
Whereas post 1 is actually the bottom message displayed above.
Summary:
your plan is good, provided you drop the sender and receiver from the
message-id - they’re unnecessary and in fact the receiver will cause
trouble (the sender is just redundant).
drop the “topic” pseudo-message-id from the References - it misleads
email clients (including TB, even if it isn’t visually evident)
cameron replies via email
discourse is sent an email with these headers from mutt:
Yes, again with the caveat that there should not be a “topic” reference.
As expected, there is a reference to the OP message-id. Though it should
be the same message-id that sam sees for the OP.
discourse (as cameron, from the above email) creates post 101
sam is sent an email from discourse with these headers:
And here it goes wrong. The Message-ID should be 43585349859734@test.com from the .incoming_post.message_id field.
(Well, in my mind this is post.message_id(), which returns post.incoming_post.message_id for an email generated post and your
Discourse generated one otherwise).
Consider: I compose and send my reply with message-id 43585349859734@test.com. For continuity reasons, I keep a copy of that
in my local folder, where it shows as a reply to the OP. Ideally
Discourse also sends me a copy of my own post (this is a policy setting
on many mailing lists), so I get Discourse’s version also. That should
have the same message-id, because it is the same message, just via a
different route.
Discourse’s message is not “in reply to” my message. It is my
message, just forwarded.
This effect cascades through your following examples. The actual process
should be simpler than you’ve made it.
Think of it this way. If I reply to a post from email, it effectively is
like me emailing sam (and the others) via Discourse. Discourse
forwards my message to the email-receiving subscribers, and
“incidentally” keeps a copy on the forum
As a side note, I also looked into what GitHub do with their
notification emails, and noticed they do a similar thing where they
have an ever-present Reference
(discourse/discourse/pull/252@github.com) that is used in all the
emails related to that “topic” which in this case is a GitHub pull
request:
Hoo, github. What a disaster their issue emails are
However, in their scenario, the PR is the OP. So a reference directly
to the pull is sane. You could use the “topic” message-id for post 1,
provided you didn’t also use the “topic/1” id as well. But there seems
little point - it is extra effort to special case post 1 - I’d just use
“topic/1” myself.
To add some complication. As I understand it, an admin can move a post
or topic. Doesn’t that break the “generate the message-id” scheme,
particularly if they move just a post? I’m somewhat of the opinion that
every post should have a _message_id field, filled in from the
incoming message (from email) or generated (posting via Discourse). Then
it is persistent and stable and robust against any shuffling of posts or
changes of algorithm.
Finally, there’s a small security consideration: you should ignore the
inbound email message-id (and potentially bounce the message) if it
claims the message-id of an existing post. Since as an author, I can put
anything I like in that header I’d go with just dropping the
message-id - accept the post, but don’t let it lie about being some
other post - give your copy the Discourse-generated id and then proceed
as normal.
Merci encore pour cette réponse merveilleusement détaillée. Il me faudra probablement un peu de temps pour assimiler tout cela et en faire des actions concrètes, alors soyez patients avec nous (en plus de cela, j’ai d’autres projets internes prioritaires sur lesquels je travaille actuellement). Je pense qu’avec ces informations, nous serons en mesure de rendre nos systèmes de threading beaucoup plus robustes et conformes aux spécifications. Je pourrais avoir d’autres questions en parcourant votre message, merci Cameron.
Par Martin Brennan via Discourse Meta le 25Juillet2022 00:28 :
Wow, merci encore pour cette réponse incroyablement détaillée. Il me faudra probablement un peu de temps pour assimiler cela et le transformer en actions concrètes, alors soyez patients avec nous (en plus de cela, j’ai d’autres projets internes de haute priorité sur lesquels je travaille actuellement). Je pense qu’avec ces informations, nous pourrons rendre nos systèmes de discussion beaucoup plus robustes et conformes aux spécifications. Je pourrais avoir d’autres questions en parcourant votre publication, merci Cameron.
C’est-à-dire qu’il a préservé mon message-id d’e-mail d’origine. Donc, le In-Reply-To est correct, et le References contient au moins mon message-id d’e-mail.
Ah, c’est une observation intéressante, je n’avais pas remarqué la petite flèche.
C’est aussi super intéressant. Je crois (sans examiner le code source) que Thunderbird fait cela, et probablement l’interface Gmail aussi, puisqu’elle fait la même chose.
Nous semblons faire cela, mais je suppose que ce n’est pas constant ? Essentiellement, nous devons nous assurer que :
TODO #1 - Si un message a un enregistrement IncomingEmail associé, nous utilisons toujours cet identifiant de message lors de l’envoi d’e-mails.
TODO #2 - Ne pas utiliser de References lors de l’envoi d’e-mails liés à l’OP du sujet.@cameron-simpson une question cependant – si l’OP a été créé via un e-mail entrant, utiliserions-nous cet Message-ID dans References pour l’OP ou l’exclurions-nous toujours ?
C’est intéressant, je pensais que chaque destinataire de l’e-mail devait avoir un Message-ID unique ? En fait, je crois que c’est pour cela que nous avons choisi d’ajouter l’unicité à l’Message-ID de chaque destinataire, pour éviter les comportements de spam, en repensant à notre sujet interne. Peut-être que @supermathie, qui fait partie de notre équipe d’infrastructure et qui a effectué de nombreux tests avec l’e-mail plus tôt cette année, pourrait également donner son avis ici ?
Ce que vous dites, c’est que c’est plutôt le message qui détermine un Message-ID unique pour tous les destinataires. Alors peut-être que nous en générons simplement un pour chaque message qui génère un e-mail ? Ensuite, nous pourrions également déplacer l’IncomingEmail.message_id ici. Tentativement, le changement que nous devrions apporter est :
TODO #3 - Ajouter un outbound_message_id à la table Post. Le générer une fois lorsqu’un e-mail est envoyé pour la première fois en relation avec le message. L’utiliser pour les en-têtes References et In-Reply-To ultérieurs. Définir sa valeur lorsqu’un message est créé à partir d’un IncomingEmail. Le format devrait être topic/:topic_id/:post_id/:random_alphanumeric_string@host par exemple topic/233499/33545/gvy8475y7c45y87554c@meta.discourse.org
Après ce changement, mon premier exemple deviendrait ceci :
Avec la considération supplémentaire que l’OP n’a pas de traitement spécial, il ne sera plus au format topic/:topic_id@hostname.
TODO #4 - S’assurer que les en-têtes In-Reply-To et References corrects sont générés en fonction des enregistrements PostReply et de la nouvelle colonne outbound_message_id dans la table Post
Je pense que nous en tenons compte, je vais vérifier.
Cela semble certainement être le cas
Pouvez-vous confirmer que les TODOs ici semblent raisonnables, Cameron ? Cela ne semble vraiment pas grand-chose maintenant que j’y regarde. Je me demande aussi, quand j’aborderai ce travail, seriez-vous ouvert à me rejoindre sur une instance Discourse de test sur laquelle les modifications WIP seraient déployées afin que nous puissions nous envoyer des e-mails et tester que les choses fonctionnent correctement ? Je ferai bien sûr mes propres tests avant de vous impliquer.
Sinon, ce n’est pas grave non plus – j’ai Thunderbird et je vais installer mutt et je pourrai tout tester là-bas
@cameron-simpson une chose que je voulais clarifier ici est la portée de « message_id ».
La chose qui a déclenché toute cette danse était un fort soupçon de la part de @supermathie que nos message_ids non uniques causaient des problèmes.
Discourse génère des e-mails uniques par utilisateur pour chaque e-mail qu’il envoie. Donc, par exemple, disons que 2 utilisateurs regardent ce sujet :
L’utilisateur 1 reçoit la charge utile 1 avec un lien de désabonnement distinct destiné à l’utilisateur 1
L’utilisateur 2 reçoit la charge utile 2 avec un lien de désabonnement distinct destiné à l’utilisateur 2
Si dans les deux cas notre identifiant de message était, disons, discourse_topic_100/23 (topic_id/post_number), alors nous dirions aux MTA que discourse_topic_100/23 peut avoir 2 charges utiles distinctes. L’hypothèse est qu’ils traitent cela comme un signal de spam.
Hé Discourse… vous venez d’envoyer deux e-mails appelés discourse_topic_100/23, qu’est-ce qui se passe ?
Étant donné que Discourse contrôle tout le transport des e-mails et que les e-mails ne sont pas ajoutés à une liste Cci ou Cci comme les listes de diffusion traditionnelles, nous pouvons nous permettre d’avoir des liens de désabonnement propres par utilisateur.
Qu’en pensez-vous ? Que pensez-vous du simple changement d’utiliser discourse_topic_100/23/7333 par exemple (topic_id, post_number, user_id) comme identifiant unique pour le courrier, c’est certainement une charge utile unique et nous pouvons facilement y faire référence lors de la génération d’e-mails pour un utilisateur.
By Martin Brennan via Discourse Meta at 26Jul2022 00:27:
[quote=“Cameron Simpson, post:11, topic:233499,
username:cameron-simpson”]
Mutt probably ignores the References
because it is a mail reader, and References originates in USENET news.
Maybe Thunderbird is using the references or augumenting the in-reply-to
with references information.
You only need to consult one of In=-Reply-To or References to do
threading; the former comes from email and the latter from USENET.
You’re supporting both (which is great!) so we need to make them
consistent.
[/quote]
This is also super interesting. I believe (without examining the source) Thunderbird does do that, and likely the Gmail UI as well since it does the same thing.
I think mutt will use both, but probably just In-Reply-To if present, falling back to References. I’d need to check the source.
With References you do at least know the full chain to the OP; with In-Reply-To you more or less need the antecedant messages around to
stitch things together. For mailing lists I usually keep the whole
thread locally until it’s done anyway, and I expect that is common.
We do seem to be doing this but I guess not consistently? Basically we need to make sure that:
TODO #1 - If a post has an associated IncomingEmail record, we always use that Message-ID when sending email.
Yes. This is why I was thinking it might be sanest to have an explicit
field for the message-id, and to fill it in once. Then use that from
then on always, regardless of any changes to the process in which the
message-id is manufactured in the code later.
TODO #2 - Do not use a References when sending out emails related to the OP of the topic .
Yes. The OP has no antecedant, so there’s no References or In-Reply-To.
@cameron-simpson one question though – if the OP was created via an
inbound email, would we use that Message-ID in References for the
OP or still exclude it?
Still exclude. But use it as the persistent message-id for the OP.
So a message authored by email (OP or reply) gets its message-id from
the email. One authored on the web gets one when the user presses
Submit, generated by Discourse. From then on, that’s the message-id,
however created.
[quote=“Cameron Simpson, post:11, topic:233499,
username:cameron-simpson”]
You can just drop the sender_user_id and receiver_user_id from the
message-id field and get a single unique id which every receiver sees.
The uniqueness constraint is the post itself, not the individual
email-level “message” object.
[/quote]
This is interesting, I thought every recipient of the email had to have a unique Message-ID?
No. The message-id identifies the “message”. Not the individual copy. I
might post to the forum and CC someone directly. If that someone gets a
copy direct from me and also via the forum, they should have the same
message-id.
In fact I believe this is why we went down the path of adding
uniqueness to each recipient’s Message-ID, to avoid spam behaviours,
looking back on our internal topic. Perhaps @supermathie , who is on
our infra team and was doing a bunch of testing with email earlier in
the year, could weigh in here too?
Maybe. But on that face of it, threading is indeed broken. Certainly
sending the same message to many people should have the same message-id,
and generally, as a forwarder (email->discourse->email-recipients)
discourse shoud not be modifying the message-ids.
What you are saying is that it’s more that the post should be the thing determining a single Message-ID for all recipients. So perhaps we just generate one for each post that generates an email?
Every post should have one stable unique message-id for use in the email
side. If the post originated from an email, that original message-id
should be used. Otherwise (via the web interface) Discourse should be
generating a message-id and storing it with the post.
Then we could also move the IncomingEmail.message_id to here as well.
Sure. Having a distinct set of fields (message-id seems enough)
containing the email-side state should do it.
Tentatively, the change we would need to make is:
TODO #3 - **Add a outbound_message_id to the Post table. Generate
it once when an email is first sent in relation to the post.
If you got the post from an email, you should be using that, not
generating a new one.
Use if for subsequent References and In-Reply-To headers. Set its
value when a post is created from an IncomingEmail.
Yes. To the message-id from the email.
Format should be topic/:topic_id/:post_id/:random_alphanumeric_string@host e.g. topic/233499/33545/gvy8475y7c45y87554c@meta.discourse.org**
For ones you generate yourselves, this looks good to me.
After this change my first example would become this:
But note: the message-id only needs to be stable and unique. If the topic/:topid_id/:post_id@host is stable and will never be regenerated,
that will do. But if you’re concerned about that (eg db restores or
migrations or imports bringing those same numbers) then the random
string will make it robust against collision.
Note that the message-id left part is dot-atom-text, defined here:
which is alphas and digits and a limited set of punctuation characters
(which includes “/”).
Note the angle brackets. The message-id is formally the bit between the
angle brackets, and the angle brackets are mandatory. Syntax here:
With the consideration also that the OP does not have special handling, it will no longer be in the format topic/:topic_id@hostname.
Sounds good.
TODO #4 - Ensure that correct In-Reply-To and References headers are generated based on PostReply records and the new outbound_message_id column on the Post table
Thanks.
I think we have some consideration for this, I will double-check.
+1
It definitely seems that way
Can you confirm the TODOs here sound reasonable Cameron?
They seem correct to me.
It really doesn’t seem like much now that I look at it. I also wonder,
when I get to this work would you be open to joining a testing
Discourse instance with me that will have the WIP changes deployed to
it so we can email back and forth and test that things are working
correctly? I will of course do testing of my own before I involve you.
Certainly. Happy to help in whatever way.
If not, that’s fine too – I have Thunderbird and will be setting up mutt and I can test it all out there
Je pense que vous pouvez toujours envoyer des messages distincts avec le même message-id, même avec de petites différences comme celle-ci.
Les listes de diffusion ordinaires font cela tout le temps à un degré ou à un autre. Au moins, certaines manipulations d’en-tête se produisent toujours. Mais le corps du message est aussi parfois modifié. Un exemple flagrant est python-list, qui rejette les pièces jointes non textuelles. Le message passe avec le même message-id cependant. Et presque toutes les listes ajoutent une note en bas avec, par exemple, un lien vers la page d’administration de la liste ou un lien de désabonnement. Cela n’aura pas été sur le message lorsqu’il est arrivé.
Et il y a eu de longues discussions sur la signature de contenu qui tournent autour de ce qui devrait être couvert par une signature.
Je serais donc tout à fait d’accord pour que vous ajoutiez votre lien de désabonnement spécifique au destinataire et que vous conserviez le message-id d’origine. Les avantages l’emportent largementlargement sur la perte de la mise en fil d’Ariane si vous donniez à chaque copie de message un message-id individuel.
Encore une fois, considérez l’utilisateur de messagerie. Je peux répondre à un message de discourse et ajouter un CC à une personne extérieure intéressée. Peut-être qu’elle reçoit une copie de discourse, peut-être pas. Mais si c’était le cas, elle devrait avoir le message-id source dessus même avec votre note supplémentaire. Sinon, elle aura 2 copies de mon message, mais son système de messagerie ne saura pas qu’il s’agit de copies du même message. Des problèmes s’ensuivent.
Donc, en bref : je ne pense pas que votre très petit texte de désabonnement supplémentaire justifie des message-ids distincts. Gardez-en un seul.
Désolé, je rattrape mon retard, voici quelques réflexions, dont certaines ont déjà été abordées…
La difficulté ici est que ce qui est envoyé depuis Discourse est un message différent de celui entrant. Il a des métadonnées différentes (à cet effet, À/De/Répondre à/Se désabonner/etc.) et un corps différent (il est personnalisé par utilisateur (je pense ? Est-ce que cela n’arrive pas en mode liste de diffusion ?)).
Quel est exactement le message ? En considérant 5322 comme parole d’évangile :
Un message se compose de champs d’en-tête, éventuellement suivis d’un corps de message.
Le champ “Message-ID:” fournit un identifiant de message unique qui fait référence à une version particulière d’un message particulier.
[emphase ajoutée]
C’est cette « version particulière » qui me fait penser qu’il serait inapproprié de renvoyer un message entrant avec un Message-ID différent. Cependant, si vous changez votre point de vue de Discourse en tant que « logiciel de forum » à Discourse en tant que « logiciel de liste de diffusion », alors cela a un peu de sens, donc je comprends votre point de vue. 5322 dit aussi :
Il existe de nombreux cas où les messages sont « modifiés », mais ces modifications ne
constituent pas une nouvelle instantiation de ce message, et par conséquent le message
ne recevrait pas un nouvel identifiant de message. Par exemple, lorsque les messages sont
introduits dans le système de transport, ils sont souvent précédés de
champs d’en-tête supplémentaires tels que des champs de trace (décrits dans la section 3.6.7)
et des champs renvoyés (décrits dans la section 3.6.6). L’ajout de tels champs d’en-tête
ne modifie pas l’identité du message et par conséquent l’original
champ “Message-ID:” est conservé. Dans tous les cas, c’est le sens que le
l’expéditeur du message souhaite transmettre (c’est-à-dire, s’il s’agit du même
message ou d’un message différent) qui détermine si le
champ “Message-ID:” change, et non une différence syntaxique particulière qui
apparaît (ou n’apparaît pas) dans le message.
Je suppose que cela se résume à la question : l’expéditeur du message change-t-il lorsque Discourse l’envoie ?
Peut-être devrions-nous utiliser Resent-Message-ID et ses amis ?
Il a toujours été là, depuis 822. Mais comme vous le dites plus tard, oui, il a été mis à jour.
5322 parle également directement de la manière dont Discourse et Github l’utilisent :
Le champ “In-Reply-To:” peut être utilisé pour identifier le message (ou les messages) auquel
le nouveau message répond, tandis que le champ “References:” peut être utilisé pour
identifier un “fil de discussion” de conversation.
Probablement de manière légèrement incorrecte, probablement en raison de l’absence d’un en-tête “Thread Identifier” approprié. Mais cette interprétation n’est peut-être pas ce que les auteurs de la RFC avaient l’intention… elle ne traite pas les messages avec des “References” mais sans “In-Reply-To”.
Le point délicat ici est que nous n’envoyons pas un e-mail, nous en envoyons N - un par destinataire - afin que leurs métadonnées individuelles (Désabonnement, etc.) puissent être correctes.
Et oui, j’ai vu des indications fortes lors des tests que la détermination du spam serait liée à un Message-ID. S’il était revu plus tard (même utilisateur ou utilisateur différent), il serait beaucoup plus susceptible d’être marqué comme spam.
Les avantages ici, pour être honnête, concernent entièrement le suivi correct des e-mails dans certains clients de messagerie, au détriment de la délivrabilité.
L’actuel topic/#{topic_id}/#{post_id}.s#{sender_user_id}r#{receiver_user_id} le rend au moins cohérent pour un utilisateur dans sa boîte aux lettres. L’hypothèse
Ma plus grande préoccupation est la délivrabilité - il est déjà assez difficile de faire livrer les e-mails lorsqu’il n’y a aucune visibilité de la part des principaux fournisseurs.
Mais je vois un argument fort pour que Discourse se comporte davantage comme un logiciel de liste de diffusion en mode liste de diffusion. @martin Je crois que nous ne personnalisons pas le corps du message en mode liste de diffusion ? Pensez-vous qu’il soit logique d’adopter une approche plus stricte concernant la conservation et la réutilisation des Message-IDs en mode liste de diffusion ?
Je ne veux pas me retrouver dans une situation où le parfait est l’ennemi du suffisamment bon.
Nous utilisons maintenant un « suffixe aléatoire » dans les messages et cela cause sans aucun doute des problèmes.
Nous avons 3 options sur la table :
Identifiants de message aléatoires impossibles à référencer
Identifiants de message stables par sujet/publication/utilisateur
Identifiants de message stables par paire sujet/publication
Nous sommes actuellement dans la situation (1) qui cause des ravages.
Je crains que nous ne tombions dans une paralysie décisionnelle entre (2) et (3).
Peut-être devrions-nous simplement commencer par (2) en reconnaissant que l’ajout de Ccs supplémentaires à un e-mail de Discourse peut entraîner un comportement inattendu, et au moins arrêter la majorité des problèmes ici ?
ah ! Je pensais que nous faisions déjà : topic/#{topic_id}/#{post_id}.s#{sender_user_id}r#{receiver_user_id}
Je serais enclin à, dans l’intérêt d’équilibrer les préoccupations d’unicité et de délivrabilité des e-mails par rapport à celles du mode liste de diffusion, faire \(2) pour le mode liste de diffusion désactivé et (3) pour le mode liste de diffusion activé.
De même, avec l’en-tête References, je serais enclin à ce qu’il soit absent pour le message n°1 d’un sujet et qu’il référence le sujet (donc topic/#{topic_id}) et le message auquel il répond, le cas échéant.