emails: add Message-Id, In-Reply-To and References headers (#89284) #1391

Merged
yweber merged 2 commits from wip/89284-email-threading into main 2024-04-30 15:03:30 +02:00
Owner
No description provided.
yweber added 1 commit 2024-04-10 10:37:04 +02:00
yweber force-pushed wip/89284-email-threading from 253aeea6a8 to 27085fb8a8 2024-04-10 10:37:50 +02:00 Compare
yweber force-pushed wip/89284-email-threading from 27085fb8a8 to 25ab1d7689 2024-04-10 10:45:31 +02:00 Compare
yweber force-pushed wip/89284-email-threading from 25ab1d7689 to 494bc3bcb7 2024-04-10 11:09:08 +02:00 Compare
yweber force-pushed wip/89284-email-threading from 494bc3bcb7 to 493463f25c 2024-04-10 11:34:03 +02:00 Compare
yweber force-pushed wip/89284-email-threading from 493463f25c to 9ede153f5f 2024-04-10 12:17:52 +02:00 Compare
yweber force-pushed wip/89284-email-threading from 9ede153f5f to 7da74513ea 2024-04-10 12:25:28 +02:00 Compare
yweber force-pushed wip/89284-email-threading from 7da74513ea to 28019d0056 2024-04-10 12:30:29 +02:00 Compare
yweber force-pushed wip/89284-email-threading from 28019d0056 to 7954dd0268 2024-04-10 12:36:22 +02:00 Compare
yweber force-pushed wip/89284-email-threading from 7954dd0268 to 73e1168ecd 2024-04-10 12:38:34 +02:00 Compare
bdauvergne reviewed 2024-04-10 13:12:11 +02:00
@ -232,0 +258,4 @@
}
return message_id
def get_references(self, formdata, addresses):
Owner

Tu peux utiliser formdata.iter_evolution_parts(klass=EmailEvolutionPart) pour factoriser un peu.

Tu peux utiliser formdata.iter_evolution_parts(klass=EmailEvolutionPart) pour factoriser un peu.
Author
Owner

Merci ! C'est fait :)

Merci ! C'est fait :)
yweber marked this conversation as resolved
yweber force-pushed wip/89284-email-threading from 73e1168ecd to 00509cd119 2024-04-10 15:09:47 +02:00 Compare
yweber force-pushed wip/89284-email-threading from 00509cd119 to 345cbb9367 2024-04-10 15:13:28 +02:00 Compare
yweber force-pushed wip/89284-email-threading from 345cbb9367 to 091ed148a9 2024-04-10 15:21:39 +02:00 Compare
yweber force-pushed wip/89284-email-threading from 091ed148a9 to e9e209e748 2024-04-10 15:32:24 +02:00 Compare
yweber changed title from WIP: emails: add Message-Id, In-Reply-To and References headers (#89284) to emails: add Message-Id, In-Reply-To and References headers (#89284) 2024-04-10 15:43:17 +02:00
fpeters requested changes 2024-04-10 18:17:33 +02:00
fpeters left a comment
Owner

(première lecture rapide)

(première lecture rapide)
@ -52,2 +54,4 @@
self.mail_subject = mail_subject
self.mail_body = mail_body
self.message_id = message_id
self.references = references
Owner

Je serais pour faire sans "references"; on ne va pas chercher à inventer une hiérarchie aux messages, faire qu'ils soient tous "enfants" du premier ça suffit.

Je serais pour faire sans "references"; on ne va pas chercher à inventer une hiérarchie aux messages, faire qu'ils soient tous "enfants" du premier ça suffit.
Author
Owner

faire qu'ils soient tous "enfants" du premier ça suffit.

Ok :) Je fais ça !

> faire qu'ils soient tous "enfants" du premier ça suffit. Ok :) Je fais ça !
yweber marked this conversation as resolved
@ -232,0 +237,4 @@
for tenant in get_publisher().get_tenants():
if tenant.directory == get_publisher().app_dir:
hostname = tenant.hostname
break
Owner

Il faut juste utiliser le tenant dans lequel on est, rien parcourir, get_publisher().tenant.hostname.

Il faut juste utiliser le tenant dans lequel on est, rien parcourir, get_publisher().tenant.hostname.
Owner

C'est ce qu'il a fait en première intention mais ça ne marche pas dans les tests de tests/workflow/test_email.py le publisher de la fixture n'est pas initialisé correctement il fait juste pub._set_request(req), et pub.tenant n'est pas créé; il doit manquer peut-être un .set_app_dir(request) ou quelque chose comme cela.

C'est ce qu'il a fait en première intention mais ça ne marche pas dans les tests de tests/workflow/test_email.py le publisher de la fixture n'est pas initialisé correctement il fait juste pub._set_request(req), et pub.tenant n'est pas créé; il doit manquer peut-être un .set_app_dir(request) ou quelque chose comme cela.
Author
Owner

il doit manquer peut-être un .set_app_dir(request) ou quelque chose comme cela.

Je confirme, l'ajout du pub.set_app_dir(req) dans la fixture résout le problème, mais c'est visiblement manquant pour d'autres tests.

La solution a privilégier serait de patcher les fixtures des tests en question (où le tenant semble mal/pas configuré) ?

> il doit manquer peut-être un .set_app_dir(request) ou quelque chose comme cela. Je confirme, l'ajout du `pub.set_app_dir(req)` dans la fixture résout le problème, mais c'est visiblement manquant pour d'autres tests. La solution a privilégier serait de patcher les fixtures des tests en question (où le tenant semble mal/pas configuré) ?
Owner

La solution a privilégier

Oui. (de manière générale le code de l'application ne doit pas contourner des déficiences dans l'infra de tests).

> La solution a privilégier Oui. (de manière générale le code de l'application ne doit pas contourner des déficiences dans l'infra de tests).
Author
Owner

Ok, le commit est en cours :)

Ok, le commit est en cours :)
yweber marked this conversation as resolved
@ -232,0 +246,4 @@
if isinstance(formdata.formdef, CardDef):
form_type = 'card'
else:
form_type = 'form'
Owner

Tu peux juste faire formdata.formdef.data_sql_prefix (ça donnera carddata ou formdata).

Tu peux juste faire formdata.formdef.data_sql_prefix (ça donnera carddata ou formdata).
Author
Owner

Cool ! Merci :)

Cool ! Merci :)
yweber marked this conversation as resolved
@ -232,0 +260,4 @@
def get_references(self, formdata, addresses):
for part in reversed(list(formdata.iter_evolution_parts(klass=EmailEvolutionPart))):
if part.addresses == addresses:
Owner

Et partant de l'idée de ne pas créer d'hiéarchie, ici il faut modifier et se contenter du premier message (correspondant aux destinataires) trouvé.

Et partant de l'idée de ne pas créer d'hiéarchie, ici il faut modifier et se contenter du premier message (correspondant aux destinataires) trouvé.
yweber marked this conversation as resolved
@ -403,0 +454,4 @@
'email_from': email_from,
'attachments': attachments,
'extra_headers': extra_headers,
}
Owner

Plutôt juste appeler ça kwargs, get_email_kwargs c'est trop un nom de fonction.

Plutôt juste appeler ça kwargs, get_email_kwargs c'est trop un nom de fonction.
Author
Owner

En effet ! C'est corrigé :)

En effet ! C'est corrigé :)
yweber marked this conversation as resolved
yweber changed title from emails: add Message-Id, In-Reply-To and References headers (#89284) to WIP: emails: add Message-Id, In-Reply-To and References headers (#89284) 2024-04-10 18:59:51 +02:00
yweber force-pushed wip/89284-email-threading from e9e209e748 to ce334f68ec 2024-04-11 09:24:09 +02:00 Compare
yweber added 1 commit 2024-04-11 09:29:45 +02:00
gitea/wcs/pipeline/head Something is wrong with the build of this commit Details
ee7c16d99e
emails: fix tests to allow simple hostname fetch in sendmail (#89284)
yweber force-pushed wip/89284-email-threading from ee7c16d99e to 5940e77177 2024-04-11 09:30:58 +02:00 Compare
yweber force-pushed wip/89284-email-threading from 5940e77177 to fe981923a3 2024-04-11 09:46:17 +02:00 Compare
yweber force-pushed wip/89284-email-threading from fe981923a3 to 55cfb3b791 2024-04-11 09:53:31 +02:00 Compare
yweber force-pushed wip/89284-email-threading from 55cfb3b791 to 37c2499446 2024-04-11 10:00:07 +02:00 Compare
yweber changed title from WIP: emails: add Message-Id, In-Reply-To and References headers (#89284) to emails: add Message-Id, In-Reply-To and References headers (#89284) 2024-04-11 10:07:49 +02:00
yweber requested review from fpeters 2024-04-11 10:07:56 +02:00
fpeters requested changes 2024-04-12 09:47:44 +02:00
@ -4135,0 +4146,4 @@
ts = datetime.datetime.now().strftime('%Y%m%d.%H%M%S.')
hostname = 'example.net'
expt_id = f'wcs-carddata-{carddef.id}-{carddata.id}.{ts}[^@]+@{hostname}'
assert re.match(expt_id, headers['Message-Id'])
Owner

Ça arrivera quand même parfois que ça foire parce qu'on n'est pas sur la même seconde; je ne vérifierais pas la partie timestamp.

Ça arrivera quand même parfois que ça foire parce qu'on n'est pas sur la même seconde; je ne vérifierais pas la partie timestamp.
Author
Owner

En effet, merci !

En effet, merci !
yweber marked this conversation as resolved
@ -47,2 +50,4 @@
def _get_message_id_re(msg_id_fmt):
return re.compile(msg_id_fmt % {'ts': datetime.datetime.now().strftime(r'%Y%m%d\.%H%M%S\.')})
Owner

pareil.

pareil.
yweber marked this conversation as resolved
@ -77,2 +84,4 @@
get_response().process_after_jobs()
assert emails.count() == 0
for part in formdata.evolution[-1].parts:
assert not isinstance(part, EmailEvolutionPart)
Owner
assert not any(isinstance(x, EmailEvolutionPart) for x in formdata.evolution[-1].parts)

(dans la suite aussi)

``` assert not any(isinstance(x, EmailEvolutionPart) for x in formdata.evolution[-1].parts) ``` (dans la suite aussi)
Author
Owner

Bonne idée, merci !

Bonne idée, merci !
yweber marked this conversation as resolved
@ -125,6 +167,12 @@ def test_email(pub, emails):
assert emails.count() == 1
assert emails.get('foobar')['to'] == 'Undisclosed recipients:;'
assert set(emails.get('foobar')['email_rcpt']) == {'foo@localhost', 'bar@localhost', 'baz@localhost'}
# recipients changed, the email is not a reply-to the previous one
Owner

Je ne suis pas sûr que ça soit adéquat comme comportement général.

Deux situations :

  • un nouvel agent dans le rôle destinataire et ça se trouve réinitialisé en mode "premier mail" pour tous les autres.
  • une démarche type signalement avec la possibilité à des usagers de s'y rattacher pour suivre les évolutions, à chaque fois qu'une nouvelle personne veut suivre ça réinitialise.

Il y aurait sans doute à faire une passe par destinataire, récupérer ainsi une liste de "first message id" et les adresses associées, et faire autant d'envois que nécessaire.

Je ne suis pas sûr que ça soit adéquat comme comportement général. Deux situations : * un nouvel agent dans le rôle destinataire et ça se trouve réinitialisé en mode "premier mail" pour tous les autres. * une démarche type signalement avec la possibilité à des usagers de s'y rattacher pour suivre les évolutions, à chaque fois qu'une nouvelle personne veut suivre ça réinitialise. Il y aurait sans doute à faire une passe par destinataire, récupérer ainsi une liste de "first message id" et les adresses associées, et faire autant d'envois que nécessaire.
Author
Owner

Je ne suis pas sûr que ça soit adéquat comme comportement général.
[...]
Il y aurait sans doute à faire une passe par destinataire, récupérer ainsi une liste de "first message id" et les adresses associées, et faire autant d'envois que nécessaire.

Oui ! J'implémente ça :)

> Je ne suis pas sûr que ça soit adéquat comme comportement général. > [...] > Il y aurait sans doute à faire une passe par destinataire, récupérer ainsi une liste de "first message id" et les adresses associées, et faire autant d'envois que nécessaire. Oui ! J'implémente ça :)
yweber marked this conversation as resolved
yweber force-pushed wip/89284-email-threading from 37c2499446 to 3bbf644749 2024-04-15 09:29:08 +02:00 Compare
yweber force-pushed wip/89284-email-threading from 3bbf644749 to 67a3986d3c 2024-04-15 12:28:26 +02:00 Compare
yweber changed title from emails: add Message-Id, In-Reply-To and References headers (#89284) to WIP: emails: add Message-Id, In-Reply-To and References headers (#89284) 2024-04-15 12:28:36 +02:00
yweber force-pushed wip/89284-email-threading from 67a3986d3c to a06864ce21 2024-04-15 12:34:46 +02:00 Compare
yweber force-pushed wip/89284-email-threading from a06864ce21 to a07d855802 2024-04-15 15:16:09 +02:00 Compare
yweber force-pushed wip/89284-email-threading from a07d855802 to f75f5a0904 2024-04-15 15:22:14 +02:00 Compare
yweber changed title from WIP: emails: add Message-Id, In-Reply-To and References headers (#89284) to emails: add Message-Id, In-Reply-To and References headers (#89284) 2024-04-15 15:22:19 +02:00
yweber force-pushed wip/89284-email-threading from f75f5a0904 to ac57ae4d8d 2024-04-15 15:22:53 +02:00 Compare
yweber force-pushed wip/89284-email-threading from ac57ae4d8d to db6c6f64ae 2024-04-15 15:39:53 +02:00 Compare
yweber requested review from fpeters 2024-04-15 15:46:25 +02:00
fpeters requested changes 2024-04-16 07:58:20 +02:00
@ -232,0 +236,4 @@
message_id = 'wcs-%(type)s-%(formdef_id)s-%(formdata_id)s.%(ts)s@%(hostname)s'
message_id %= {
Owner

Détail de style mais plutôt mettre le % sur la ligne du haut, on n'utilise pour ainsi dire jamais %=.

Détail de style mais plutôt mettre le % sur la ligne du haut, on n'utilise pour ainsi dire jamais %=.
Author
Owner

Ok !

Ok !
yweber marked this conversation as resolved
@ -232,0 +248,4 @@
def get_first_messages_id(self, formdata, addresses):
remaining = set(addresses)
result = {}
for part in list(formdata.iter_evolution_parts(klass=EmailEvolutionPart)):
Owner

Il n'est normalement pas nécessaire de passer list() ici.

Il n'est normalement pas nécessaire de passer list() ici.
Author
Owner

En effet, merci !

En effet, merci !
yweber marked this conversation as resolved
@ -394,2 +428,4 @@
for first_id, id_addr in self.get_first_messages_id(formdata, addresses).items():
message_id = self.get_message_id(formdata)
formdata.evolution[-1].add_part(
EmailEvolutionPart(
Owner

Je serais pour avoir un seul EmailEvolutionPart par contenu, ça sera important quand on voudra afficher ceux-ci dans l'interface. (l'agent voudra voir que le message a bien été envoyé à n personnes, ne sera pas intéressé par le fait que le message a en fait été découpé en trois envois parce que tout le monde n'a pas pris le fil dès le début).

Mais il faut peut-être quand même avoir plusieurs message-id, pour que si jamais on doit logguer en aval (genre exim), la distinction y existe. Donc EmailEvolutionPart, j'ai l'impression quil faut a voir un dictionnaire message_ids, pour y avoir la correspondance message-id ←→ destinataire.

A priori de mesures rapides il n'y a pas de danger que deux appels successifs à get_message_id() donnent le même résultat, il faut plus d'une microseconde pour en générer un.

Je serais pour avoir un seul EmailEvolutionPart par contenu, ça sera important quand on voudra afficher ceux-ci dans l'interface. (l'agent voudra voir que le message a bien été envoyé à n personnes, ne sera pas intéressé par le fait que le message a en fait été découpé en trois envois parce que tout le monde n'a pas pris le fil dès le début). Mais il faut peut-être quand même avoir plusieurs message-id, pour que si jamais on doit logguer en aval (genre exim), la distinction y existe. Donc EmailEvolutionPart, j'ai l'impression quil faut a voir un dictionnaire message_ids, pour y avoir la correspondance message-id ←→ destinataire. A priori de mesures rapides il n'y a pas de danger que deux appels successifs à get_message_id() donnent le même résultat, il faut plus d'une microseconde pour en générer un.
Author
Owner

En effet, bonne idée !

En effet, bonne idée !
yweber marked this conversation as resolved
@ -427,0 +451,4 @@
email_kwargs = {
**common_kwargs,
**dest_kwargs,
'extra_headers': {'Message-Id': message_id, **reply_headers},
Owner

(mets plutôt Message-ID, avec ID en majuscule, c'est davantage commun).

(mets plutôt Message-ID, avec ID en majuscule, c'est davantage commun).
Author
Owner

Bien vu ! Merci :)

Bien vu ! Merci :)
yweber marked this conversation as resolved
yweber force-pushed wip/89284-email-threading from db6c6f64ae to 836b7a96b5 2024-04-16 09:11:02 +02:00 Compare
yweber requested review from fpeters 2024-04-16 09:20:08 +02:00
fpeters approved these changes 2024-04-26 15:31:31 +02:00
fpeters left a comment
Owner

Je valide mais j'ai posé une petite demande de commentaire.

Je valide mais j'ai posé une petite demande de commentaire.
@ -232,0 +255,4 @@
if len(remaining) == 0:
break
else:
result[None] = (self.get_message_id(formdata), list(remaining))
Owner

Je verrais bien une ligne de commentaire pour expliciter le cas où on se trouve à utiliser None.

Je verrais bien une ligne de commentaire pour expliciter le cas où on se trouve à utiliser None.
Author
Owner

Oui, merci ! C'est ajouté.

Oui, merci ! C'est ajouté.
yweber marked this conversation as resolved
yweber force-pushed wip/89284-email-threading from 836b7a96b5 to 649ae79ca1 2024-04-29 09:29:09 +02:00 Compare
yweber force-pushed wip/89284-email-threading from 649ae79ca1 to af25e206da 2024-04-30 14:48:28 +02:00 Compare
yweber merged commit af25e206da into main 2024-04-30 15:03:30 +02:00
yweber deleted branch wip/89284-email-threading 2024-04-30 15:03:30 +02:00
Sign in to join this conversation.
No reviewers
No Label
No Milestone
No Assignees
3 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: entrouvert/wcs#1391
No description provided.