Résumé

  • Dans IMAP, CLOSE ramenait la connexion de l’état Selected à l’état Authenticated, mais supprimait aussi définitivement tous les messages portant le drapeau \Deleted, sans réponses EXPUNGE individuelles.
  • RFC 3691 a défini UNSELECT, qui libère les ressources de la boîte sélectionnée sans expunger. Le protocole a ainsi séparé un changement de contexte d’une décision irréversible sur les données.

Le mot « fermer » paraît administratif. On ferme une fenêtre, une session de travail ou un dossier parce qu'on n'en a plus besoin. Dans IMAP, ce mot portait pourtant une conséquence durable. Sur une boîte sélectionnée en écriture, CLOSE ne se contentait pas de rendre les ressources au serveur : il supprimait définitivement chaque message déjà marqué \Deleted.

Le client pouvait n'avoir aucune intention de confirmer ces suppressions. Il pouvait vouloir conserver la connexion authentifiée, passer à une autre tâche ou réduire l'état maintenu par le serveur. Les drapeaux pouvaient provenir d'une opération antérieure ou d'une autre session. La commande choisie pour sortir devenait néanmoins celle qui franchissait le point de non-retour.

L'extension UNSELECT, publiée dans le RFC 3691 en 2004, a corrigé cette confusion avec un verbe minuscule. Elle ramène elle aussi la connexion de Selected à Authenticated et libère les ressources liées à la boîte. Sa différence tient dans une négation essentielle : aucun message n'est supprimé définitivement.

Cette histoire ne porte donc pas seulement sur le courrier électronique. Elle montre pourquoi deux chemins qui atteignent le même état ne détiennent pas forcément la même autorité.

Sélectionner une boîte créait un contexte de protocole

Après l'authentification, un client IMAP ne peut pas agir arbitrairement sur les messages. Il choisit une boîte avec SELECT ou l'ouvre en lecture seule avec EXAMINE. La connexion entre alors dans l'état Selected. Recherches, lectures, changements de drapeaux, copies et suppressions prennent sens dans ce contexte.

Le serveur doit conserver des informations utiles à cette vue : nombre de messages, changements de drapeaux et autres événements de boîte. Quitter Selected peut donc libérer une ressource réelle sans fermer la connexion réseau ni mettre fin à l'identité authentifiée.

Le schéma d'état originel donnait cette fonction à CLOSE. Après un succès, la connexion revenait à Authenticated. Mais un schéma qui ne montre que les nœuds de départ et d'arrivée cache ce qui arrive aux données sur l'arête. CLOSE effectuait également l'expunge des messages marqués.

Le drapeau \Deleted n'était pas encore la disparition. Il signalait qu'un message devait être retiré lors d'un expunge ultérieur. Cette séparation permettait de marquer plusieurs éléments puis de revoir la décision. Elle créait aussi une distance entre l'acteur qui posait le drapeau et celui qui déclenchait la suppression finale.

En réunissant sortie et expunge, CLOSE faisait du dernier geste de rangement le mandataire de toutes les marques accumulées.

L'économie de réponses n'était pas une absence d'effet

La commande EXPUNGE ordinaire retire définitivement les messages \Deleted et envoie une réponse non étiquetée pour chaque retrait. Ces réponses utilisent les numéros de séquence, c'est-à-dire les positions courantes dans la boîte. Lorsqu'un message disparaît, les positions suivantes se déplacent ; la série de réponses décrit cette évolution.

CLOSE ne transmet pas cette série. Le choix avait une justification pratique. Un client qui quitte la boîte n'utilisera probablement plus ses positions. S'il y a beaucoup de messages à retirer, ne pas produire des notifications bientôt inutiles peut être nettement plus rapide.

Mais une trace courte n'implique pas une opération bénigne. La réponse étiquetée OK confirme l'achèvement de CLOSE; elle ne certifie ni l'absence de suppression ni la liste de ce qui a disparu. La performance venait précisément du fait que l'inventaire individuel n'était pas envoyé.

Le mode de sélection modifiait encore le résultat. Si la boîte avait été ouverte avec EXAMINE ou était autrement en lecture seule, CLOSE ne retirait aucun message et n'émettait pas d'erreur parce que rien n'avait été retiré. Même jeton, même transition d'état, réussite possible dans les deux cas — mais effets persistants différents.

Une preuve exploitable doit donc réunir le nom canonique de la boîte, le mode lecture-écriture, l'ensemble des messages marqués avant la commande, le verbe choisi et la réception de son résultat. Un simple événement « boîte fermée » efface la question décisive.

Avant UNSELECT, la sortie sûre passait par un détour

IMAP4rev1 connaissait déjà des sorties sans expunge. Le client pouvait sélectionner ou examiner une autre boîte, ou envoyer LOGOUT, sans appeler d'abord CLOSE. La sélection courante se terminait implicitement et les messages marqués n'étaient pas retirés à cause de cette transition.

Il manquait cependant une commande directe pour le cas suivant : ne plus sélectionner aucune boîte, rester authentifié, ne rien supprimer. Le RFC 3691 décrit deux solutions utilisées avant la normalisation. Le client pouvait tenter de sélectionner une boîte inexistante, en exploitant l'échec pour revenir à Authenticated. Il pouvait aussi sélectionner de nouveau la même boîte avec EXAMINE.

La première méthode transformait un échec attendu en contrôle normal. Les journaux ne pouvaient plus séparer la sortie intentionnelle d'une faute de nom. Les compteurs d'erreur perdaient leur sens. Une future correction d'implémentation pouvait casser un comportement devenu dépendance. La seconde méthode ouvrait une vue en lecture seule afin de se débarrasser d'une vue en écriture, alors que le client ne voulait plus de vue du tout.

Ces détours prouvaient que l'état final était accessible. Ils prouvaient aussi que le vocabulaire du protocole n'exprimait pas l'intention. Une extension utile n'a pas nécessairement besoin d'ajouter un pouvoir ; elle peut donner un nom honnête à un pouvoir que le client ne voulait justement pas exercer.

La capability empêchait de deviner la sémantique

Un serveur IMAP4rev1 prenant en charge l'extension annonçait la capability UNSELECT. Le client pouvait vérifier cette compréhension avant d'envoyer la commande. Le rejet d'un mot inconnu ne pouvait pas être traité comme une sortie réussie : la connexion pouvait rester Selected et le serveur conserver ses ressources.

La négociation évitait les suppositions fondées sur la marque du logiciel ou son âge. Elle ne prouvait pas l'identité de l'utilisateur, l'exactitude de l'interface ou l'intégrité du contenu. Elle établissait seulement un langage partagé et la promesse étroite attachée à ce mot.

UNSELECT n'a pas d'argument et ne requiert pas de réponses non étiquetées propres à la commande. Une réponse étiquetée signale l'achèvement. Sa sûreté ne vient pas d'un reçu détaillé, mais du fait que le sens convenu exclut la suppression permanente.

Cette précision aide aussi en cas de panne. Si le résultat n'arrive pas, le client doit reconnaître l'incertitude de l'état au lieu de déclarer la ressource libérée. Mais il n'a pas à craindre qu'une nouvelle tentative d'UNSELECT répète une suppression. Réduire l'étendue de l'effet réduit l'étendue du risque après une réponse perdue.

UNSELECT préservait la décision, pas le message pour toujours

La commande n'enlève pas le drapeau \Deleted. Elle ne restaure rien de ce qui a déjà été expungé et ne dit pas qui a posé une marque. Après une nouvelle sélection, les mêmes drapeaux peuvent encore être présents. Un EXPUNGE, un futur CLOSE ou une opération ciblée peut alors retirer les messages.

UNSELECT protège donc un moment de décision. Sortir maintenant ne vaut pas consentement à rendre définitives toutes les marques. Ce n'est ni un verrou de concurrence ni une politique de conservation. D'autres sessions restent capables de modifier l'état selon leurs droits.

Cette limite empêche d'attribuer au protocole une garantie imaginaire. La capability ne remplace pas l'autorisation. Le résultat de commande ne prouve pas qu'une copie de sauvegarde existe. Le serveur ne connaît pas nécessairement l'intention humaine derrière chaque drapeau. La promesse vérifiable reste simple : cette commande de sortie n'effectue pas l'expunge.

IMAP4rev2 a rendu la séparation normale

Le RFC 9051 a intégré UNSELECT au jeu de commandes de base d'IMAP4rev2. Sa description d'état place CLOSE et UNSELECT parmi les transitions vers Authenticated. Les définitions maintiennent pourtant leur différence : dans une boîte accessible en écriture, CLOSE retire les messages marqués ; UNSELECT n'en retire aucun.

Le passage d'une capability d'extension au protocole de base conserve la mémoire d'une réparation mesurée. Il n'a pas prétendu que les anciens chemins n'existaient plus. Il a rendu l'intention courante lisible sans dépendre d'un faux échec ou d'une resélection artificielle.

La leçon dépasse IMAP. Fermer une connexion après commit et la fermer après rollback produit le même état de connexion, pas le même état de données. Libérer un fichier après flush ou après abandon du tampon ne raconte pas la même histoire. Une télémétrie qui ne garde que la destination perd le contrôle exercé en chemin.

Avec UNSELECT, le protocole a retiré une permission implicite. Demander la libération d'une ressource ne suffit plus à autoriser la suppression définitive. Pour franchir cette frontière, le client doit choisir un acte qui la porte explicitement.

Une confirmation perdue ne laissait pas le même risque

La connexion peut tomber après réception de la commande par le serveur mais avant le résultat étiqueté. Avec UNSELECT, l'incertitude porte surtout sur le maintien éventuel de l'état Selected. Avec CLOSE, elle porte aussi sur une suppression qui peut déjà avoir eu lieu. Rejouer mécaniquement le dernier appel n'est donc pas une stratégie neutre.

Une récupération sérieuse se reconnecte, observe la boîte et rapproche les UID encore présents des preuves antérieures avant de réappliquer une intention humaine. Elle distingue la restauration d'un contexte de la répétition d'un commit. Une bibliothèque devrait faire la même différence dans son interface : « libérer la sélection » ne peut pas cacher CLOSE derrière un destructeur générique.

Le résultat OK n'est pas un inventaire des messages. La force d'UNSELECT est de rendre la classe d'effet explicite avant l'envoi, lorsque le choix peut encore être revu, au lieu de demander à l'opérateur de la déduire après une réponse minimale.

Sources