Skip to main content
La fédération permet à deux serveurs OxiMail, tenus chacun par une organisation différente, de se répondre directement : aucun hub au milieu, aucun compte invité, aucun annuaire partagé. Elle sert aujourd’hui deux choses, toutes deux en lecture seule :
  • Le temps occupé d’une organisation à l’autre. Chercher un créneau avec quelqu’un d’une organisation appairée lit son libre/occupé sur son propre serveur. À l’inverse, une organisation appairée peut lire le temps occupé de vos personnes, chacune sous son propre consentement.
  • Des dossiers du Drive partagés avec une organisation appairée. L’exploitant du propriétaire partage un dossier ou un fichier en lecture. L’autre côté le montre, en lecture seule, dans un compte miroir de son propre Drive.
La fédération est désactivée par défaut. Un serveur qui ne fédère jamais ne détient aucune clé de fédération, ne monte aucune route et répond exactement comme un serveur sans cette fonction. Tout ce que décrit cette page vaut par organisation (tenant) : une box qui héberge plusieurs organisations les appaire chacune séparément, sous son propre realm.
Le transport fédéré est récent (octobre 2026) et volontairement étroit : deux chemins de lecture, ouverts par les administrateurs des deux côtés, jamais par découverte. Le dépôt de courrier entre serveurs, les salons de chat fédérés et l’écriture dans un dossier partagé sont spécifiés dans les brouillons et ne sont pas servis. Voir ce qui n’est pas servi.

Le modèle de confiance

Trois décisions façonnent tout le reste. Chacune existe parce que l’autre option laisserait quelqu’un d’autre que les deux administrateurs décider qui est digne de confiance. L’appairage lie deux organisations et se décide hors bande. Un appairage nomme un realm (le domaine de l’organisation, partner.example). Il est écrit par une cérémonie d’exploitant de chaque côté, après que les deux administrateurs ont comparé leurs empreintes de vive voix. Il n’existe pas de « découvrir puis accepter » : une cérémonie qui fait confiance au premier qui répond ne vaut rien. Le DNS ne fait jamais parler ce serveur à un serveur avec lequel il n’est pas appairé. L’identité a deux moitiés. Ce qu’un pair épingle, ce sont les racines d’identité de l’organisation : de deux à cinq clés sœurs (trois par défaut), chacune mise sous séquestre sous sa propre clé papier, détenue par l’organisation (un coffre, un associé, un second bureau). Le serveur seul ne peut jamais les reconstituer. Ce qui signe les requêtes, c’est une clé de travail sur la box, certifiée par une racine pour une fenêtre de validité (365 jours par défaut). Faire tourner la clé de travail ne demande rien à aucun pair : ils ont épinglé les racines, et les racines se portent garantes de la suivante. Chaque clé de travail porte une époque qui ne fait que croître. Elle vaut la plus grande de deux valeurs : l’époque précédente plus un, ou l’horloge en secondes. Une rotation est donc une révocation, et une base restaurée depuis un état plus ancien ne réemploie jamais une époque que les pairs ont déjà vue. Un pair qui réémet une époque sous une autre clé (ou un identifiant de clé connu lié à une autre clé) est refusé. Chaque requête et chaque réponse est signée, sur du HTTPS ordinaire. Une requête fédérée va au point d’entrée /jmap/federation du pair, sur son port HTTPS habituel. Elle est signée selon le profil RFC 9421 du brouillon de fédération : elle nomme les deux realms, porte son nonce dans le champ d’en-tête JMAP-Federation et le certificat de la clé de travail dans JMAP-Federation-Certificate. Elle est vérifiée sur ses champs d’en-tête (profil, fraîcheur, appairage, certificat contre les racines épinglées, signature, nonce, époque) avant qu’un seul octet de son contenu soit lu ; le contenu est plafonné à 64 Kio. Le certificat voyage avec la requête : aucune requête ne fait donc aller chercher des clés au serveur qui la reçoit. Une requête créée avant le démarrage du processus qui la reçoit est refusée, ce qui ferme le rejeu à travers un redémarrage. Les réponses sont signées de la même façon, et vérifiées avant qu’on en utilise la moindre partie. Les épingles TLS enregistrées à l’appairage sont contrôlées pendant la poignée de main, en plus de la validation ordinaire du certificat, jamais à sa place.

Trois niveaux, jamais confondus

Un grant élargit qui peut demander, jamais ce qui est vu : il n’atteint que les agendas que la personne compte déjà dans sa disponibilité, et la réponse porte des périodes occupées, jamais un événement. Un partage de nœud ouvre un dossier ou un fichier et tout ce qui se trouve en dessous, jamais ce qui est à côté ou au-dessus. Ni l’un ni l’autre ne crée de principal local pour le pair : le pair ne devient jamais membre, lecteur ou groupe de cette box. Le grain est l’organisation. Une requête fédérée prouve quel serveur demande, pas laquelle de ses personnes a agi. Un grant qui nommerait une personne à l’autre bout n’aurait donc que l’air d’être plus étroit. La conséquence se dit telle quelle : l’exploitant de l’autre organisation peut lire ce qui est partagé avec cette organisation, et federation shares add le dit dans sa simulation. Le côté JMAP des grants et des divulgations est décrit sur la page du partage.

La juridiction

Chaque côté enregistre la juridiction de l’autre, un code pays ISO 3166-1 alpha-2 (CH, DE, FR), saisi à l’appairage et figé dans chaque grant accordé à cette organisation : le consentement a été donné à une contrepartie située quelque part. Votre propre juridiction est le pays d’établissement déclaré de l’organisation (oximail tenant identity set --tenant <id> --establishment-country CH --apply), sinon celui hérité de l’opérateur d’instance. federation identity le lit à voix haute à côté des empreintes, federation pair enregistre ce qu’il a déclaré à chaque pair, et doctor avertit quand le pays déclaré aujourd’hui diffère de ce qu’un pair s’est vu dire (lignes doctor).

Ce qui quitte la box, et ce qui n’en sort pas

La liste des organisations avec lesquelles vous êtes appairé regarde l’organisation. Chaque ligne de fédération de oximail doctor compte les appairages et les partages et ne nomme jamais un realm, et aucune métrique de fédération ne porte d’étiquette de pair : la ronde et les métriques quittent la box pour la supervision. oximail federation peers list et oximail federation shares list les nomment, sur la box. La porte a sa propre classe de bannissement : un échec de fédération ne bannit pas une adresse pour le courrier et le web, ni l’inverse.

Avant d’appairer

  1. Ouvrez la porte dans la section [federation] (configuration), avec l’URL à laquelle les pairs joindront ce serveur. Son chemin doit être /jmap/federation, et un proxy inverse placé devant doit livrer ce chemin sans le modifier : le pair le signe.
  2. Déclarez le pays d’établissement de l’organisation, pour que l’autre côté ait une juridiction à enregistrer pour vous.
  3. Publiez l’enregistrement de fédération dans le DNS une fois la porte ouverte (plus bas). Il sert au temps occupé ; les chemins du Drive utilisent le point d’entrée enregistré à l’appairage.
Le serveur refuse de démarrer (code de sortie 2) avec enabled = true sans point d’entrée au chemin de la porte, et quand l’adresse enregistrée d’un pair se trouve dans [security] trusted_ips : les adresses de confiance contournent le limiteur de débit et le compteur de bannissement qui protègent la porte.

Appairer deux organisations

Les deux administrateurs suivent les mêmes étapes, chacun sur son serveur, l’autre au téléphone. Chaque verbe est une simulation tant que --yes n’est pas passé.
1

Créer l'identité (une fois par organisation)

La première exécution est toute la cérémonie en une commande : elle crée le jeu de racines (--roots, de 2 à 5, trois par défaut ; une seule est refusée, car une racine unique est un point de défaillance unique), met chaque racine sous séquestre sous sa propre clé papier, affiche ces clés papier une seule fois, et certifie une clé de travail (--valid-days, 365 par défaut). --custody est obligatoire : une étiquette par racine, pour qu’on puisse dire plus tard où se trouve chaque sœur. Le realm ne peut plus changer ensuite : cela réancrerait chaque pair.
2

Lire vos empreintes à l'autre administrateur

La commande affiche une empreinte de racine par sœur (calculée sur le realm et la racine : la confirmer, c’est s’accorder sur les deux), votre juridiction, et l’empreinte de transport : le realm, le point d’entrée, la méthode, la source de clé, le rôle et les épingles TLS triées de votre section [federation]. Lisez-les ; notez les siennes.
3

Simuler l'appairage

Passez chaque racine qu’il a lue (--key se répète : n’épingler qu’une sœur ferait casser l’appairage au premier remplacement de sœur). La simulation rapporte des faits : s’il existe déjà un appairage, si chaque clé figure déjà dans le jeu inscrit de ce realm, les grants qui nomment ce realm, chaque empreinte de racine et l’empreinte de transport à comparer. --tls-pin se répète (la clé en service et la suivante, quatre au plus) ; sans épingle, le certificat du pair est validé comme d’habitude et rien n’est épinglé. On n’omet --endpoint que pour un pair que ce serveur n’appelle jamais.
4

Confirmer les deux valeurs, puis épingler

--yes est refusé sans --transport-fingerprint, ou avec une valeur qui ne correspond pas. Les lignes de racine couvrent les clés ; la ligne de transport couvre le point d’entrée, les épingles et la façon dont le pair s’authentifie. Une cérémonie qui n’aurait comparé que l’une des deux laisserait substituer l’autre. Rien n’est écrit en cas de refus.
5

Vérifier

peers list montre chaque appairage avec son état et le transport qu’il a enregistré. Dès que les deux côtés ont épinglé, l’appairage sert.
Un tunnel posé par vous. Si les deux sites sont reliés par un tunnel que vous exploitez, --address <ip> enregistre une adresse privée littérale (ou partagée, 100.64.0.0/10) pour joindre l’hôte de ce pair, et de ce pair seulement. Ce n’est jamais une plage, jamais une adresse de trusted_ips, et elle ne fait pas partie de l’empreinte de transport : c’est votre routage, que l’autre côté ne connaît pas. TLS vérifie toujours le nom du point d’entrée. Aucun tunnel n’est intégré au serveur, et aucun n’est nécessaire quand les deux sites ont une adresse publique. Quand l’appairage change. federation peers unpair --realm … --yes suspend un appairage, il ne le supprime jamais : les grants qui nomment cette organisation cessent d’autoriser tant qu’il dort, et restent la décision de leurs sujets. peers suspend --cause … nomme le fait qui manque (admin-unpaired, key-mismatch, anchor-unconfirmed, restore-unconfirmed), car la cause décide de l’acte qui la lève ; peers resume ne lève qu’une rupture administrative. Une clé discordante ou une ancre non confirmée (après une restauration de base, ou pour un appairage antérieur au modèle d’ancre) se soigne en relançant federation pair avec la racine actuelle du pair.

L’enregistrement DNS

Un domaine qui fédère annonce son point d’entrée sous son propre enregistrement SRV :
L’hôte et le port sont ceux de [federation] endpoint. L’enregistrement sert à une seule chose : router une question de temps occupé au sujet d’une adresse. Quand quelqu’un cherche un créneau avec carol@partner.example, le serveur lit l’enregistrement _jmap-federation._tcp de partner.example par le résolveur validant de la box. Il ne l’utilise que s’il est sûr au sens DNSSEC et que sa cible est l’hôte du point d’entrée enregistré pour exactement un appairage actif. Pas d’enregistrement, une zone non signée, aucun appairage correspondant : personne n’est interrogé. Les chemins du Drive ne lisent jamais le DNS : ils appellent le point d’entrée enregistré à l’appairage. Ce n’est jamais l’enregistrement _jmap._tcp des clients. Un client JMAP standard suit les cibles de cet enregistrement avec les identifiants de l’utilisateur, et le brouillon de fédération peut y nommer le serveur d’un autre exploitant. Cet enregistrement ne peut pas non plus dire qu’un domaine fédère, puisque n’importe quel fournisseur JMAP le publie.
  • oximail setup dns le publie (par l’API Cloudflare) ou affiche sa ligne de zone, seulement une fois [federation] activée. Une installation neuve ne fédère jamais : l’enregistrement apparaît quand vous relancez setup dns après avoir ouvert la porte.
  • oximail check-dns et la ligne dns de oximail doctor le vérifient quand la porte est ouverte, et ne le valident que s’il est signé DNSSEC : un pair ne route sur rien d’autre. Un enregistrement non signé est nommé à part d’un résolveur qui n’a pas pu prouver sa réponse.

Le temps occupé d’une organisation à l’autre

Chaque personne décide qui peut lire son temps occupé : un grant nomme une organisation appairée. Il est créé par la personne seule, en JMAP (un administrateur peut révoquer, jamais accorder), et expire au bout d’un an sauf si la personne choisit explicitement autre chose (partage). oximail federation grants list montre chaque grant avec sa dernière utilisation ; federation grants revoke --id … --yes en coupe un. Révoquer retire le chemin de lecture pour la suite et ne défait rien de ce qui a déjà été divulgué. Quand un pair interroge ce serveur. Un serveur appairé relaie Principal/getAvailability pour 50 adresses au plus, sur une fenêtre de 62 jours au plus ; une requête qui dépasse l’une ou l’autre limite est refusée, jamais tronquée. La réponse ne porte que du temps occupé fusionné : aucun événement, aucun titre, aucune enveloppe d’heures de travail. Une adresse inconnue, une personne qui n’a rien accordé et une personne libre tout le temps donnent la même réponse : la porte ne sert pas d’oracle d’annuaire. Une adresse hors des domaines de courrier de l’organisation reçoit une réponse incomplète, avec la raison notServed, jamais « libre » : une route erronée apparaît donc comme incertaine. Une divulgation par personne est enregistrée, en une transaction, avant que la réponse parte : la personne la lit dans son journal des divulgations. Quand ce serveur interroge un pair. Event/proposeTimes confie au demandeur fédéré les adresses de participants qu’aucun compte local ne détient. Celui-ci route chacune par l’enregistrement DNS, interroge les pairs en parallèle (cinquante adresses par appel) et attend quatre secondes en tout, routage compris. Une réponse n’est utilisée qu’une fois sa signature vérifiée. Un pair qui n’a pas donné de réponse vérifiée à temps place ses participants dans unreachableEmails, jamais libres ; une réponse distante incomplète les place dans incompleteFor (agenda). Porte fermée, un grant n’autorise rien et personne n’est interrogé.

Partager des dossiers du Drive

Côté propriétaire : un partage par nœud

L’exploitant partage un dossier ou un fichier du Drive, en lecture, avec une organisation appairée. Il n’existe pour cela aucune surface JMAP ni web : la CLI est le seul rédacteur.
Le nœud se désigne par --path (depuis la racine du Drive du propriétaire) ou par --node <id>, le propriétaire par --owner-email ou --owner-account-id. La simulation résout le nœud, vérifie chaque règle et dit ce que l’exploitant de l’autre organisation pourra lire. --expires-at <RFC 3339> fixe une échéance facultative. Il n’y en a aucune par défaut, faute de durée décidée : un partage dure jusqu’à ce qu’on le retire. --json donne une réponse lisible par une machine. Un partage est refusé, nommément, dans ces cas : Un partage sert tant que son appairage est actif et que son échéance n’est pas passée (shares list affiche active, expired ou peering-inactive). Chaque acte est consigné dans la chaîne d’audit de l’organisation (federation.share.created, federation.share.removed). Un partage est retiré, consigné et signalé aussitôt au serveur lecteur, quelle que soit la cause : shares remove, le nœud supprimé définitivement, le balayage de la corbeille, l’effacement du propriétaire. Il ne disparaît jamais en silence avec une ligne supprimée. Ce que l’autre organisation a déjà lu n’est pas défait. Par la porte, le pair lit avec FileNode/get, FileNode/query et FileNode/changes, bornés au sous-arbre partagé : un parent, un frère, un nœud non partagé ou dans la corbeille répondent exactement comme un nœud inconnu. Le contenu est servi sur une seconde route, /jmap/federation/content, par blocs signés de 1 Mio. Chaque bloc est demandé par nœud, contenu attendu et plage, jamais par un identifiant de blob nu : les blobs sont dédoublonnés, et un identifiant nu répondrait à la question « ce fichier existe-t-il quelque part sur ce serveur ». La divulgation du propriétaire est enregistrée au plus une fois par heure, par propriétaire et par organisation. Chaque appairage a un budget par classe, pour qu’une copie de dossier n’affame jamais les lectures de temps occupé : disponibilité 20 requêtes par seconde (rafale de 40), fichiers 20 (rafale de 100), contenu 50 blocs par seconde (rafale de 100), et au plus huit lectures de contenu en cours par appairage. Un budget épuisé répond limit.

Côté lecteur : le compte miroir

Ce qu’une organisation appairée partage avec vous apparaît dans un compte miroir : un compte partagé de votre organisation dont le Drive montre les dossiers que ce realm partage avec ce serveur.
mirror add --apply crée un compte partagé, sans connexion possible, avec une racine de Drive (nom affiché « Shared by » suivi du realm, ou --display-name), et le déclare miroir : la capability federation {realm} sur son principal. La commande est refusée, nommément, quand le realm n’est pas un appairage actif avec un point d’entrée enregistré (not-paired, peering-not-active), ou quand il a déjà son miroir (already-mirrored). L’accès s’accorde sur le compte, jamais nœud par nœud. mirror remove retire la capability, et le serveur purge la copie à son passage suivant ; le compte reste. Le miroir suit quatre règles :
  • Rien du propriétaire sur ce disque. Le serveur copie l’arborescence partagée par la porte du pair, en mémoire seulement : aucune ligne de Drive, aucun blob, rien dans les sauvegardes, rien qu’une révocation pourrait manquer. Le prix, dit tel quel : à chaque redémarrage, l’arborescence est recopiée, et les clients du miroir reçoivent cannotCalculateChanges puis se resynchronisent.
  • Au plus mirror_staleness_secs de retard. Le serveur demande les changements au propriétaire à chaque moitié de cette borne (120 s par défaut), et aussitôt quand le propriétaire envoie un avis. Un sous-arbre révoqué part aussitôt, et un appairage qui n’est plus actif purge la copie.
  • Lecture seule pour tout le monde. Toute écriture sur un compte miroir, par n’importe quel client et n’importe quel rôle, est refusée avec mirror-read-only.
  • Jamais un dossier vide. Tant que la copie n’est pas prête, la liste montre à la place un fichier d’état nommé : (copy in progress from partner.example), (partner.example unreachable since …), (access revoked by partner.example) ou (no active pairing with partner.example). Un propriétaire injoignable laisse en place l’arborescence déjà chargée.
mirror list fonctionne serveur arrêté et montre l’état de l’appairage de chaque miroir. L’état de la copie elle-même vit dans le serveur en cours (la métrique oximail_federation_mirrors{state} : copying, ready, unreachable, revoked, unpaired).

Ouvrir un fichier miroir

Un fichier miroir se télécharge comme les autres, par les portes de téléchargement web et JMAP, mais son contenu est lu chez le propriétaire, par nœud, un bloc signé de 1 Mio à la fois par la route de contenu du propriétaire (au plus huit blocs en cours par appairage, dix secondes par bloc), jamais dans le magasin de blobs de ce serveur. Un cache en mémoire, indexé par la version du contenu, absorbe les réouvertures d’un même geste (une suite bureautique ouvre plusieurs fois le même fichier) : une durée de content_cache_secs, content_cache_mib en tout, des fichiers jusqu’à content_cache_file_mib. Un fichier plus gros est lu chez le propriétaire à chaque fois (configuration). Le cache n’est jamais écrit sur le disque, et il oublie les blocs d’un nœud avec le nœud. Un propriétaire injoignable est refusé nommément (ownerUnreachable, 503), que le contenu soit en cache ou non : il n’existe pas de copie hors connexion. Un fichier miroir n’a pas de vignette.
Une page de mémoire peut tout de même atteindre le swap ou un core dump, tous deux sur le volume que doctor mesure (chiffrement au repos). Un exploitant qui veut exclure même cela désactive le swap et les core dumps pour le service.

Configuration

endpoint et tls_pins sont ce que ce serveur annonce à ses pairs pendant la cérémonie : les changer change votre empreinte de transport, et chaque pair doit enregistrer la nouvelle. Les bornes sont vérifiées au démarrage du serveur porte ouverte (code de sortie 2 sur une valeur hors bornes) et par la ligne federation_content_cache de doctor ; check-config ne les vérifie pas.

Garder l’identité en bon état

Lignes doctor et métriques

Les métriques ne portent aucune étiquette de pair : oximail_federation_door_requests_total{class,outcome} (ce que la porte a répondu), oximail_federation_door_content_octets_total (le contenu partagé servi), oximail_federation_mirrors{state}, oximail_federation_content_reads_total{source} et oximail_federation_content_octets_total{source} (remote ou cache), oximail_federation_content_cache_octets et oximail_federation_content_cache_blocks, et oximail_federation_grants_expiring{tenant} (exploitation).

Ce qui n’est pas servi

La fédération sert les deux chemins de lecture ci-dessus, et rien d’autre. En particulier :
  • Pas de courrier entre serveurs. Le dépôt, le rôle de spool et le dépôt scellé sont spécifiés dans les brouillons ; la capability de transport les annonce absents.
  • Pas d’appairage dans la bande. L’appairage passe uniquement par la cérémonie en CLI ; un serveur n’annonce aucune méthode d’appairage dans la bande, et un domaine qui publie un enregistrement de fédération n’est jamais contacté avant qu’un humain l’appaire.
  • Pas d’identité au niveau de la personne. Le bénéficiaire est une organisation ; les requêtes ne sont pas signées par personne.
  • Pas d’écriture dans un dossier partagé. Les comptes miroirs sont en lecture seule. Un seul éditeur à la fois, avec un bail pris chez le propriétaire, et des dossiers épinglés « toujours disponibles hors connexion » au site lecteur sont prévus, pas construits. Aucun contenu n’est servi tant que le propriétaire est injoignable.
  • Pas de partage depuis un client. Les partages de nœud ne s’écrivent qu’en CLI, et la racine d’un Drive ne se partage jamais.
  • Pas de jauge de joignabilité par appairage, et pas d’échec de doctor quand un appairage actif est injoignable : décidé, pas construit.
La surface JMAP des grants et des divulgations est décrite sur la page du partage, le compte miroir vu par un client sur la page des fichiers, et les verbes dans la référence CLI.