Résumé

  • La RFC 10022 permet à un client IMAP d’obtenir des plages d’UID descendantes proches d’un nombre demandé de messages, notamment en mode UIDONLY. Ces plages préparent un travail ultérieur ; elles ne constituent ni un instantané ni un résultat de recherche mémorisé.
  • Les UID de début et de fin peuvent ne correspondre à aucun message. Un lot peut être plus petit que demandé, diminuer après des suppressions et représenter un coût très différent selon l’opération, la taille des messages et l’état du serveur.
  • Daniel Eggert a édité le document de consensus de l’IETF. La valeur de sa contribution tient aussi à sa limite : le protocole coordonne un découpage minimal sans s’approprier la planification du client ni la preuve du résultat.

Un client demande 2 000 messages par lot. Le premier intervalle contient surtout des notifications en texte court. Le suivant couvre des années de pièces jointes. Le compteur est proche dans les deux cas ; le second transfert dure vingt fois plus longtemps. L’étiquette « page 2 sur 40 » efface déjà l’information la plus importante : la commande n’a jamais promis des pages de poids égal.

Publiée en juillet 2026 sur la voie Standards Track de l’IETF, la RFC 10022, IMAP UIDBATCHES Extension, a pour éditeur Daniel Eggert d’Apple Inc. Elle répond à un besoin précis : déterminer à l’avance des plages d’UID assez petites pour limiter le nombre de messages visés par des commandes ultérieures, y compris lorsque UIDONLY interdit l’usage des numéros de séquence.

Le mécanisme est utile parce qu’il reste étroit. Il fournit une partition. Le client doit encore établir ce que cette partition contenait réellement, combien elle a coûté et si le travail attendu a abouti.

L’égalité porte sur une cible de comptage

Le client indique un nombre de messages par lot, avec un minimum de 500. Le serveur ne doit jamais renvoyer une plage contenant davantage de messages que demandé. Il devrait viser le nombre exact et, lorsque c’est possible, rester au-dessus de 90 %. Il peut néanmoins descendre plus bas si cela simplifie ou améliore sensiblement l’implémentation, ou si la boîte change pendant le calcul. Le dernier lot recueille normalement le reste.

Cette règle ne borne pas les octets. Elle ne borne pas la durée d’un FETCH, le coût d’un SEARCH, les écritures déclenchées par STORE, la décompression, l’indexation ou la mémoire du client. Même la taille de la réponse n’est qu’une possibilité de réduction, pas une garantie.

Un ordonnanceur sérieux conserve donc deux types de mesures. Le protocole donne la cible et les plages. L’exécution donne le nombre de messages réellement touchés, les octets, la durée côté serveur et côté client, les erreurs et les reprises. Sans cette seconde série, adapter la taille du lot revient à régler une machine en regardant seulement le nombre inscrit sur le bouton.

La distinction est aussi économique. Une équipe peut vouloir protéger la latence, une autre la mémoire, une troisième le temps avant le premier résultat visible. Le même nombre de messages ne répond pas automatiquement à ces trois objectifs. La politique locale doit nommer la ressource qu’elle cherche à contenir.

Une plage d’UID n’énumère pas ses membres

Les réponses sont ordonnées des UID les plus élevés vers les plus faibles. Cela permet de commencer par les messages les plus récents. Mais les bornes de la plage peuvent désigner des UID qui n’existent pas. Des suppressions ont laissé des trous, et le serveur dispose d’une marge pour choisir des limites efficaces.

Ainsi, 163886:99703 peut couvrir approximativement le nombre souhaité de messages sans qu’un message 163886 ou 99703 soit présent. La dernière plage peut se terminer par 1 alors que le plus faible UID existant vaut 302. Le 1 sert à signaler sans ambiguïté que la plage atteint le bas de la boîte ; il ne crée pas un message.

Il est donc faux de calculer la population par soustraction des bornes. Il est tout aussi faux de conclure qu’un UID inclus arithmétiquement existait lors de la réponse. Seule la commande suivante dira quels messages ont été trouvés, lus ou modifiés.

Le dossier de preuve doit garder cette séparation. La réponse UIDBATCHES est une instruction de découpage. Le résultat d’un FETCH, SEARCH ou STORE est une observation ou une action. Les fusionner dans un seul objet « page » rend impossible l’explication d’un trou plus tard.

La boîte conserve son propre temps

Les nouveaux messages reçoivent des UID plus élevés et n’apparaissent donc pas à l’intérieur d’une plage déjà renvoyée. Son nombre de messages ne peut pas augmenter. Il peut diminuer lorsqu’un message est expurgé.

La RFC 10022 demande au client de ne pas recalculer à volonté. Un nouvel appel est approprié après la sélection d’une autre boîte, lorsque plus de la moitié d’un lot a été supprimée, ou lorsqu’au moins une demi-taille de lot de nouveaux messages est arrivée. En dehors de ces cas, le client ne doit pas répéter UIDBATCHES. Le calcul peut être coûteux, et le serveur devrait faire respecter la limite.

Les événements EXPUNGE, VANISHED et EXISTS deviennent ainsi des éléments de décision. Il faut enregistrer leur cumul depuis le calcul précédent et le seuil franchi. Un simple bouton « actualiser les pages » masque une décision de charge que le protocole a précisément encadrée.

L’identité de la boîte est plus fondamentale encore. Les UID n’ont de sens que dans la boîte sélectionnée et sous une valeur UIDVALIDITY. Une plage mise en cache puis réutilisée après un changement de boîte ou de validité n’est pas seulement ancienne : elle a perdu son référentiel. Serveur, compte, boîte et UIDVALIDITY doivent précéder les bornes dans tout reçu.

Le recoupement révèle que les fenêtres ne sont pas figées

Une réponse peut être limitée à certains indices de lots. Dans une très grande boîte, un client demandera peut-être 1:100 puis 101:200. Or le nombre par lot est approximatif et l’état peut changer entre les requêtes. La RFC propose alors de recouper la frontière : 1:100, 100:200, 200:300.

Le lot répété permet de comparer les plages et de détecter une incohérence possible. Il ne la résout pas. Il ne prouve pas non plus que les deux fenêtres sont cohérentes lorsqu’une comparaison superficielle réussit. La politique du client doit décider s’il recommence, élargit le recoupement, poursuit avec avertissement ou bloque un résultat sensible.

Ce détail distingue UIDBATCHES d’une API de pagination avec jeton d’instantané. Le numéro de lot est une position de calcul par rapport aux UID les plus élevés au moment considéré. Il n’est pas un identifiant durable de page.

La limite de 100 000 messages pour une demande de plage protège le serveur. Celui-ci doit pouvoir fournir au moins cette étendue, mais peut renvoyer TOOMANY pour un travail plus grand, y compris une demande de toutes les plages d’une boîte immense. Avec MESSAGELIMIT, le client devrait en outre ne pas demander plus de messages que la limite annoncée par commande.

Une réponse vide doit conserver sa question

Une boîte vide produit une réponse UIDBATCHES sans plage, suivie d’un succès. Mais une boîte non vide produit la même forme lorsque les indices demandés n’existent pas. « Zéro lot » ne suffit pas à distinguer les deux.

Le tag relie la réponse à sa commande. Les indices demandés donnent le périmètre. EXISTS fournit l’état de sélection. L’interface doit conserver les trois. Sans eux, elle peut annoncer « boîte vide » alors qu’elle a seulement interrogé les lots 6 à 8 d’une boîte qui en compte quatre.

Les codes TOOFEW, TOOMANY et LIMIT ont la même importance. Un lot trop petit risquerait de reconstituer une information positionnelle que UIDONLY cherche à retirer. Des demandes répétées ou trop vastes peuvent épuiser les ressources. Un code précis est une raison de politique, pas une erreur générique à réessayer immédiatement.

UIDBATCHES n’est d’ailleurs ni SEARCH ni UID SEARCH. Avec SEARCHRES, le serveur ne doit pas enregistrer son résultat dans $. La partition reste séparée d’un ensemble de résultats sauvegardé. PARTIAL, de son côté, fournit des opérations paginées de SEARCH et FETCH ; il résout un autre problème.

Situer Daniel Eggert sans agrandir son rôle

Au 1er septembre 2026, le profil officiel de Daniel Eggert dans l’IETF Datatracker recensait les RFC 10022 et 9979. Une annonce Swift.org de 2022 sur SwiftNIO IMAP le présentait comme membre de l’équipe Apple travaillant sur Mail pour iOS et macOS et renvoyait vers son identité GitHub publique.

Ce contexte daté rend compréhensible son travail sur une frontière client-serveur. Il ne prouve pas qu’un produit Apple déterminé implémente la RFC, qu’Eggert dirige le comportement d’un serveur déployé ou qu’il possède le consensus de l’IETF. L’éditeur contribue au texte ; chaque implémentation et chaque résultat de service ont leurs propres responsables.

La contribution collective respecte le principe de spécification initiale minimale décrit par Heng Lu. Le protocole expose le fait commun nécessaire : des plages permettant de répartir le nombre de messages. Il laisse au serveur son algorithme, au client sa planification et à l’opérateur son objectif. La primauté du code en fonctionnement impose ensuite de regarder les commandes réellement exécutées et les résultats observés.

Le reçu minimal d’un lot

Conserver d’abord le serveur, la frontière de compte, la boîte sélectionnée et UIDVALIDITY. Ajouter les capacités, le tag, le nombre demandé, les indices éventuels, le code de réponse et les plages exactes. Associer ensuite EXISTS, EXPUNGE et VANISHED, le seuil de recalcul et les recoupements entre fenêtres.

Pour chaque plage, enregistrer la commande suivante, les UID réellement rencontrés, les messages absents, les octets, les durées, les erreurs, la reprise et le point de contrôle local. Le contenu privé et les secrets n’ont pas à entrer dans un journal public ; des compteurs, identifiants bornés, hachages et temps suffisent à rendre la décision vérifiable.

La plage garde alors sa juste valeur. Elle organise le travail sans prétendre arrêter le temps de la boîte.

Sources