[Corrigé 3.2.62] Réponse à un mail de notification crée un nouveau ticket

Vous avez trouvé un bug dans l'application (dernière version stable ou bêta): Décrivez le ici afin que la correction soit intégrée a la prochaine version.
Répondre
arobasyk
Gsup LEVEL 2
Messages : 39
Enregistré le : jeu. 8 nov. 2018 14:20

Bonjour,

Je viens de me rendre compte que lorsqu'un utilisateur répond à un mail de notification, cela crée systématiquement un nouveau ticket au lieu d'ajouter au suivi du ticket ouvert.
J'ai installé la Beta 3.2.62.
Version 3.2.17 // IIS 10
Avatar du membre
Flox
Administrateur du site
Messages : 9883
Enregistré le : jeu. 21 juin 2012 19:00

Bonjour,

pouvez-vous transmettre une impression écran des paramètres de votre connecteur ?

Cdt
GestSup: 3.2.53 | Debian: 12 | Apache: 2.4.59 | MariaDB: 11.5.2 | PHP: 8.3 | https://doc.gestsup.fr/
arobasyk
Gsup LEVEL 2
Messages : 39
Enregistré le : jeu. 8 nov. 2018 14:20

Bonjour.
Voici les informations demandées.
Fichiers joints
2026-08-26_15h26_20.png
2026-08-26_15h26_20.png (59.92 Kio) Vu 136 fois
2026-08-26_15h26_04.png
2026-08-26_15h26_04.png (71.68 Kio) Vu 136 fois
Version 3.2.17 // IIS 10
Avatar du membre
Flox
Administrateur du site
Messages : 9883
Enregistré le : jeu. 21 juin 2012 19:00

Bonjour,

je ne reproduis pas ce problème de mon côté, pouvez-vous le reproduire sur un hébergement d'essai gratuit ?

Cdt
Fichiers joints
2026-08-27 16_04_39-Greenshot.png
2026-08-27 16_04_39-Greenshot.png (33.83 Kio) Vu 104 fois
GestSup: 3.2.53 | Debian: 12 | Apache: 2.4.59 | MariaDB: 11.5.2 | PHP: 8.3 | https://doc.gestsup.fr/
arobasyk
Gsup LEVEL 2
Messages : 39
Enregistré le : jeu. 8 nov. 2018 14:20

Il n'y a pas de connecteur imap et SMTP sur l'hébergement de test....
Pour information, j'ai remarqué le phénomène après avoir modifié le texte des notifications dans les états des tickets.
Version 3.2.17 // IIS 10
Avatar du membre
Flox
Administrateur du site
Messages : 9883
Enregistré le : jeu. 21 juin 2012 19:00

GestSup: 3.2.53 | Debian: 12 | Apache: 2.4.59 | MariaDB: 11.5.2 | PHP: 8.3 | https://doc.gestsup.fr/
Tom
Gsup LEVEL 1
Messages : 10
Enregistré le : lun. 23 sept. 2024 13:00

Bonjour Flox,

Je complète ce sujet avec une analyse complète. Deux défauts distincts, dans la même construction (celle commentée "encoding fix #6068"), avec un correctif que j'ai appliqué et validé en production ce jour. L'environnement détaillé est en fin de message : ma page Système s'affiche mal derrière mon reverse proxy, j'ai donc tout listé à la main.

1. Symptômes

Deux comportements, que j'ai longtemps confondus de mon côté :

a) Le titre des tickets créés par mail contient un bloc d'en-tête brut :

Code : Tout sélectionner

TEST
Thread-Topic: TEST
Thread-Index: AQHdOh+HVnL2t5QAR0a0KMEYtYfOWQ==
Date: Tue, 1 Sep 2026 16:38:2
(tronqué à 100 caractères par tincidents.title varchar(100))

b) Le titre perd tous ses caractères non-ASCII, et toute réponse à une notification crée un nouveau ticket au lieu d'alimenter l'existant :

Code : Tout sélectionner

attendu : Re: Notification de déclaration pour le ticket n°8306 : TEST RÉPONSE
obtenu  : Re: Notification de dclaration pour le ticket n8306 : TEST RPONSE
Aucun des deux n'est systématique : le comportement dépend de la longueur de l'objet, donc du repliement de l'en-tête Subject. C'est ce qui rend le diagnostic difficile.

2. Le code concerné — core/imap_oauth.php

Code : Tout sélectionner

//get subject with encoding fix #6068
$header=$imap_mail->getHeader();
$subject=$header->find("/Subject: \"?([^\"]*)[\";\s]/");
if(!$subject) { $subject=$imap_mail->getSubject();}
if(!$subject){$subject=T_('(Sans objet)');}

#convert encoding
$subject = iconv_mime_decode($subject, ICONV_MIME_DECODE_CONTINUE_ON_ERROR, "UTF-8");

#sanitize subject
$subject=htmlspecialchars($subject, ENT_QUOTES, 'UTF-8');
Défaut 1 — la capture de find() déborde sur tout l'en-tête

[^\"]* est gourmand, et une classe de caractères négative matche les retours à la ligne. Sur un en-tête Subject non replié, la capture avale donc tout le bloc d'en-tête jusqu'au prochain guillemet double — chez moi le boundary=" du Content-Type. Ce bloc est ensuite stocké tel quel comme titre du ticket.

Défaut 2 — double décodage RFC 2047

La variable $subject peut contenir deux représentations différentes :
- via find() : l'en-tête brut, encoded-words RFC 2047 inclus. iconv_mime_decode() est le bon traitement.
- via getSubject() : l'objet DÉJÀ décodé par Webklex. iconv_mime_decode() reçoit alors du texte 8 bits, illégal dans un en-tête RFC 2047, et avec ICONV_MIME_DECODE_CONTINUE_ON_ERROR il supprime silencieusement chaque octet non-ASCII au lieu d'échouer.

Le décodage étant appliqué inconditionnellement aux deux branches, la seconde est détruite.

3. Quelle branche est empruntée, et pourquoi ça change tout

Le motif de find() exige "Subject: " avec une espace littérale après les deux-points. Quand le client replie l'en-tête sur des lignes de continuation, il ne correspond plus :

Code : Tout sélectionner

Subject:
 =?utf-8?B?UmU6IE5vdGlmaWNhdGlvbiBkZSBkw6ljbGFyYXRpb24gcG91ciBsZSB0aWNr?=
 =?utf-8?B?ZXQgbsKwODMwNyA6IFJlOiBOb3RpZmljYXRpb24gZGUgZGNsYXJhdGlvbiBw?=
 =?utf-8?Q?our_le_ticket_n8306_:_TEST_RPONSE_2?=
Donc : objet court non replié -> défaut 1 (bloc d'en-tête dans le titre)
objet long replié -> défaut 2 (non-ASCII détruits)

Or l'objet d'une notification GestSup est long par construction. core/mail.php ligne 364 :

Code : Tout sélectionner

$object=T_($robject['mail_object']).' '.T_('pour le ticket').' n°'.$db_id.' : '.htmlspecialchars_decode($globalrow['title'], ENT_QUOTES);
Chez moi cet objet fait 105 octets, au-delà de la limite de 78 caractères par ligne du RFC 5322. Le repliement est inévitable, et la réponse y ajoute encore "Re: ". Toute réponse à une notification emprunte donc la branche du défaut 2.

4. Conséquence sur le rattachement au ticket

Code : Tout sélectionner

$c_reg = "/n°(.*?):/i"; //regex to find ticket number
Le motif exige le caractère ° (U+00B0, octets C2 B0), que le défaut 2 vient précisément de supprimer. Aucune correspondance, donc passage dans la branche "case create new ticket". Un défaut d'encodage produit une duplication de tickets.

5. Preuve côté base (tincidents.title, même colonne, même connexion)

Code : Tout sélectionner

id 8306  objet court, non replié
  title : TEST RÉPONSE 2
  hex   : 544553542052C389504F4E53452032
                      ^^^^ C3 89 = É conservé

id 8307  objet long, replié
  title : Re: Notification de dclaration pour le ticket n8306 : TEST RPONSE 2
  hex   : 52653A...2064636C61726174696F6E...206E38333036...
                    aucun C3 A9 (é), aucun C2 B0 (°)
La base n'est pas en cause : elle transporte C3 89 sans perte sur la ligne 8306.

6. Correctif proposé — deux modifications localisées

Défaut 1 : borner la capture à une seule ligne d'en-tête.

Code : Tout sélectionner

$subject=$header->find("/Subject: \"?([^\"\r\n]*)[\";\s]/");
Défaut 2 : ne décoder que si des encoded-words sont réellement présents. Idempotent, sans effet sur la branche find().

Code : Tout sélectionner

#convert encoding - only when RFC 2047 encoded-words are actually present
if (preg_match('/=\?[^?]+\?[BQbq]\?/', $subject)) {
    $subject = iconv_mime_decode($subject, ICONV_MIME_DECODE_CONTINUE_ON_ERROR, "UTF-8");
}
7. Validation en production

Appliqué sur mon instance 3.2.62 le 01/09/2026, php -l OK.

Avant correctif :

Code : Tout sélectionner

[mail 1] mail data : subject="TEST
Thread-Topic: TEST
Thread-Index: AQHdOh+HVnL2t5QAR0a0KMEYtYfOWQ==
Date: Tue, 1 Sep 2026 16:38:27 +0200
[...tout le bloc d'en-tête jusqu'au boundary="...]"
[mail 1] create new ticket
[mail 1] ticket created : 8317

[mail 1] mail data : subject="Re: Notification de dclaration pour le ticket n8317 : TESTThread-Topic:..."
[mail 1] create new ticket
[mail 1] ticket created : 8318
Après correctif :

Code : Tout sélectionner

[mail 1] mail data : subject="TEST ENCOR ENCORE V2 OU 3 JE SAIS PLUS"
[mail 1] create new ticket
[mail 1] ticket created : 8320

[mail 1] mail data : subject="Re: Notification de déclaration pour le ticket n°8320 : TEST ENCOR ENCORE V2 OU 3 JE SAIS PLUS"
[mail 1] update existing ticket : 8320
Objet propre, accents conservés, rattachement rétabli.

8. Périmètre

core/imap_basic.php ne contient pas ce double décodage (ligne 204 : htmlspecialchars directement). Les deux défauts ne concernent donc que le chemin Webklex, c'est-à-dire les modes d'authentification oauth_azure, login2 et oauth_google. Le mode login historique n'est pas affecté.

9. Deux suggestions annexes

a) Message de debug ambigu. La branche de rattachement teste deux conditions :

Code : Tout sélectionner

if($find_ticket_number && $rparameters['imap_reply'])
mais affiche "create new ticket" dans tous les cas d'échec. Distinguer "numéro de ticket introuvable dans l'objet" de "option Gérer les réponses aux mails désactivée" ferait gagner beaucoup de temps en diagnostic.

b) Risque de faux positif sur $c_reg. Le motif /n°(.*?):/i s'applique à tout mail entrant, y compris à un mail neuf. Un objet du type "Facture n°4521 : relance" sera rattaché au ticket 4521 s'il existe, ou insérera un thread orphelin s'il n'existe pas — le SELECT sur tincidents ne vérifie pas que la ligne existe. En français, "n°" est très courant en correspondance commerciale. Deux pistes : vérifier la présence d'un en-tête In-Reply-To ou References, ou ancrer le motif sur le libellé mail_object configuré plutôt que sur "n°" seul.

10. Environnement

Code : Tout sélectionner

GestSup            : 3.2.62 (beta), montée depuis 3.2.61 le 01/09/2026
                     core/imap_oauth.php : @Update 19/08/2026, @Version 3.2.62
Langue serveur     : fr_FR

OS                 : Debian 12 (conteneur Docker)
Déploiement        : Docker Compose, deux conteneurs (gestsup + mariadb),
                     reverse proxy en frontal
Serveur web        : Apache 2.4, libapache2-mod-php, écoute sur 8081
PHP                : 8.2.7 (mod_php)
Extensions PHP     : common, curl, gd, imap, intl, ldap, mbstring, mysql, xml, zip
php.ini            : max_execution_time=480, memory_limit=512M,
                     upload_max_filesize=8M, date.timezone=Europe/Paris,
                     expose_php=Off, default_charset=UTF-8

Base               : MariaDB (image officielle), conteneur séparé
                     innodb_buffer_pool_size=4G, skip-name-resolve
Charsets           : character_set_client     = utf8mb3
                     character_set_connection = utf8mb3
                     character_set_database   = utf8mb3
                     character_set_results    = utf8mb3
                     character_set_server     = utf8mb4
Table              : tincidents DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
                     tincidents.title varchar(100) NOT NULL

Connecteur IMAP    : outlook.office365.com:993 (IMAP sécurisé)
                     Vérification SSL : activée
                     Dossier racine : INBOX
                     Date de création du ticket : date du mail
                     Authentification : XOAUTH2 Azure (Entra ID)
                     Gérer les réponses aux mails : activé
                     Multi boîte aux lettres par service : désactivé
                     Création automatique des utilisateurs : désactivée
                     Action post-traitement : passer en lu

Connecteur SMTP    : smtp.office365.com:587 (TLS)
                     Vérification SSL : activée
                     Classe : isSMTP()
                     Authentification : XOAUTH2 Azure (Entra ID)

Appel mail2ticket  : cron externe sur l'hôte
                     docker exec -d gestsup php /var/www/html/mail2ticket.php
                     toutes les minutes, 6h-20h, du lundi au vendredi

Clients expéditeurs: Microsoft Outlook / Exchange Online (Microsoft 365)
Je n'ai pas pu déterminer à quelle version la construction #6068 a été introduite. Le correctif ci-dessus est en place chez moi, je reste disponible pour tester une version amont.

Cordialement,
Tom
Répondre