Pourquoi vous en avez besoin
mailcow fournit une API d’administration. Elle est parfaite pour créer des domaines, des boîtes et des alias, mais elle ne dit rien du courrier contenu dans une boîte. Si vous voulez qu’un script, un CRM ou un workflow d’automatisation lise une boîte partagée, réponde en tant que cette adresse ou classe un message dans un dossier, l’API d’administration vous laisse vous débrouiller seul.
La Mailbox API pour mailcow comble ce manque. Elle donne à vos propres programmes une interface REST contrôlée sur le courrier lui-même : lister dossiers et messages, chercher, lire un message complet avec pièces jointes, envoyer en tant que la boîte, marquer, déplacer ou supprimer. En plus, chaque boîte surveillée peut pousser chaque nouveau message vers un webhook https au format JSON signé, et vers un chat Telegram. Tout tourne à l’intérieur de votre réseau mailcow, et vous décidez quelles boîtes et quels droits chaque clé obtient.
Ce tutoriel déroule l’installation comme je l’ai faite sur mon propre serveur : d’abord les clés, puis la lecture et l’envoi, puis les webhooks vers un outil d’automatisation comme n8n, et enfin les alertes Telegram.
Prérequis
- mailcow-dockerized sur Linux avec docker compose et systemd, et le mailcow Toolkit 0.5.0 ou plus récent de MediaLab Works installé (ce produit est l’un de ses modules, avec sa propre licence).
- Un accès root sur l’hôte pour lancer l’installeur du Toolkit, et un accès HTTPS sortant depuis le serveur vers
medialab.workspour la vérification de licence. - Une adresse https pour l’API, utilisée dans les liens signés des pièces jointes, et, pour les webhooks, un point de terminaison https qui vous appartient.
- Facultatif : un jeton de bot Telegram fourni par @BotFather et l’identifiant de chat de chaque boîte à notifier.
- Le module est open source (GPL-3.0), vous recevez donc le code source complet.
Étape 1 — Installer le module et activer la licence
Le module est livré dans le paquet du Toolkit. Sur l’hôte mailcow, en root, lancez l’installeur comme d’habitude :
sudo ./install.sh --mailcow-dir /opt/mailcow-dockerized --name <instance>
Il copie data/web/mlw-mailbox-api/, ajoute l’entrée de menu, la tâche de l’agent hôte et le minuteur qui s’exécute chaque minute, puis recharge php-fpm. Ouvrez ensuite System → Mailbox API dans le menu d’administration mailcow ; vous verrez une bannière de licence et les réglages en dessous.
Pour activer, ouvrez System → Updates (Toolkit) et trouvez la carte Mailbox API for mailcow : collez la clé et activez-la, ou démarrez l’essai. En ligne de commande, c’est aussi possible avec php /web/mlw-toolkit/cli.php activate mailcow-mailbox-api <KEY> dans php-fpm-mailcow. La licence est vérifiée chaque jour ; sans internet, le module continue de fonctionner 7 jours après la dernière vérification réussie. Sans licence valide, l’API répond 503 not_licensed et le minuteur n’envoie rien, mais les boîtes et les messages ne sont pas touchés.
Étape 2 — Activer l’API et régler les bases
Dans System → Mailbox API :
- API on active ou désactive l’API. La licence est vérifiée dans tous les cas.
- Public API address est l’adresse utilisée dans les liens signés des pièces jointes, par exemple
https://mail.example.com/mlw-mailbox-api/. Laissez vide pour la déduire de la page. - Messages per page (1–200) et largest attachment (1–100 MB) fixent vos limites.
- Dovecot master user est facultatif et ne sert que si vous avez défini le vôtre dans
mailcow.conf; par défaut, le module lit les identifiants master que mailcow crée au démarrage. - Telegram bot token est facultatif pour l’instant ; nous y revenons à l’étape 6.
Étape 3 — Créer des clés limitées
Dans la carte API keys, donnez un nom à la clé, cochez les droits nécessaires — read, send, organize — choisissez les boîtes qu’elle peut utiliser, puis appuyez sur Create key. La clé (mbx_…) n’est affichée qu’une fois, au moment de sa création : stockez-la tout de suite. La liste montre le préfixe, les droits, les boîtes et la dernière utilisation ; Revoke la désactive immédiatement. Seul le SHA-256 d’une clé est stocké en base, et chaque appel est journalisé.
C’est le point que je préfère pour l’automatisation : un workflow qui ne fait que classer le courrier entrant dans des dossiers reçoit une clé avec organize sur une seule boîte, et rien d’autre. Un script de notification reçoit uniquement read. Vous ne confiez jamais une clé qui peut atteindre toutes les boîtes du serveur.
Envoyez la clé à chaque appel :
Authorization: Bearer mbx_…
Étape 4 — Lire et organiser le courrier
Toutes les routes s’appellent sur https://<mail host>/mlw-mailbox-api/?r=<route> — le nginx de mailcow n’a pas de PATH_INFO, la route vit donc dans la chaîne de requête. Les réponses sont en JSON. Toutes les routes sauf le lien signé des pièces jointes exigent la clé, et la clé doit autoriser la boîte et le droit.
Commencez par vérifier ce qu’une clé peut faire :
curl -H "Authorization: Bearer $KEY" \
"https://mail.example.com/mlw-mailbox-api/?r=/v1/me"
GET /v1/me renvoie le nom de la clé, les droits, les boîtes et les limites ; GET /v1/mailboxes liste les boîtes autorisées avec leur nombre de dossiers et l’UIDNEXT de INBOX. Pour voir les dossiers et une page des messages les plus récents :
curl -H "Authorization: Bearer $KEY" \
"https://mail.example.com/mlw-mailbox-api/?r=/v1/folders&mailbox=office@example.com"
curl -H "Authorization: Bearer $KEY" \
"https://mail.example.com/mlw-mailbox-api/?r=/v1/messages&mailbox=office@example.com&folder=INBOX&limit=20&offset=0&unseen=1"
La liste des messages accepte q= pour la recherche et unseen=1 pour les non lus uniquement, et revient du plus récent au plus ancien avec uid, objet, expéditeur, destinataire, date, taille et état lu. Lire un message donne le texte, le HTML, les en-têtes et les pièces jointes (nom, type, taille, url signée) :
curl -H "Authorization: Bearer $KEY" \
"https://mail.example.com/mlw-mailbox-api/?r=/v1/messages/1234&mailbox=office@example.com&folder=INBOX"
Les pièces jointes arrivent sous forme de liens signés qui expirent au bout d’une heure et sont liés à la clé API qui peut lire la boîte : vous pouvez donc les télécharger sans faire circuler la clé. Régénérer un lien suppose de relire le message via l’API.
Avec le droit organize, vous pouvez marquer lu ou non lu, déplacer et supprimer :
curl -X POST -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \
-d '{"read":true}' \
"https://mail.example.com/mlw-mailbox-api/?r=/v1/messages/1234/read&mailbox=office@example.com&folder=INBOX"
curl -X POST -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \
-d '{"folder":"Archive"}' \
"https://mail.example.com/mlw-mailbox-api/?r=/v1/messages/1234/move&mailbox=office@example.com&folder=INBOX"
Un DELETE sur /v1/messages/{uid} supprime définitivement le message. Les erreurs sont en JSON avec un statut HTTP : 401 clé absente ou incorrecte, 403 la clé n’a pas de droit sur cette boîte, 404 route ou message inconnu, 422 entrée invalide, 429/502 limites ou erreur serveur.
Étape 5 — Envoyer en tant que la boîte
L’envoi exige le droit send. Le corps accepte to, subject et text, et prend aussi en charge cc, bcc, html et reply_to. Une copie est placée dans Sent, ce qui compte si quelqu’un ouvre ensuite cette boîte et se demande ce qui a été répondu :
curl -X POST -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \
-d '{"to":"customer@example.org","subject":"Your invoice","text":"Attached."}' \
"https://mail.example.com/mlw-mailbox-api/?r=/v1/send&mailbox=office@example.com"
Rien n’est envoyé à medialab.works ; le message part par votre propre mailcow.
Étape 6 — Webhooks pour le nouveau courrier, vérifiés
Dans la carte Monitored mailboxes, ajoutez une boîte, le dossier à surveiller (INBOX par défaut), une adresse de webhook en https et, facultativement, un identifiant de chat Telegram. Le module vérifie chaque minute les nouveaux messages via l’UIDNEXT de chaque dossier. Notez le principe : le premier passage ne fait que fixer le point de départ, aucun ancien courrier n’est rejoué — le nouveau courrier à partir de ce moment est livré.
Chaque nouveau message produit un POST JSON avec event, mailbox, folder, uid, received_at et un objet message contenant message_id, date, expéditeur, destinataire, cc, objet, taille, texte, html, en-têtes et pièces jointes (nom, type, taille, sha256 et url signée).
Avant d’utiliser le corps, vérifiez l’en-tête de signature :
X-MLW-Signature: t=1792300000,v1=<hex HMAC-SHA256(secret, "t.body")>
X-MLW-Event: message.received
Chaque moniteur a son propre secret, généré à la première utilisation ; la page l’affiche à la création du moniteur et via le bouton Secret. Comparez le HMAC avec votre secret et rejetez les horodatages de plus de cinq minutes. Dans n8n, par exemple, placez cette vérification dans un petit nœud Code ou Function juste après le nœud Webhook, avant que quoi que ce soit d’autre ne touche la charge utile.
Les livraisons échouées sont réessayées après 30 s, 1 min, 2 min… jusqu’à cinq tentatives. Les livraisons sont mises en file en base et envoyées par le minuteur qui s’exécute chaque minute, et la carte Recent deliveries montre le statut et la réponse — votre premier réflexe quand un workflow semble silencieux.
Étape 7 — Notifications Telegram par boîte
Collez le jeton du bot sous Settings (il est stocké chiffré, seuls les quatre derniers caractères sont affichés ; un seul bot sert toutes les boîtes). Indiquez ensuite l’identifiant de chat — un utilisateur, un groupe ou un canal — sur chaque boîte surveillée. Le bot doit en être membre et, pour les canaux, administrateur. Telegram à côté d’une boîte envoie un message de test. La notification affiche l’expéditeur, l’objet et les 400 premiers caractères du texte.
C’est un bon usage pour une boîte partagée : un chat par boîte surveillée, et vous voyez le nouveau courrier sur votre téléphone sans ouvrir de client mail.
Astuces et dépannage
503 not_licensed: activez la licence sous System → Updates (Toolkit) ; sans internet, le module fonctionne 7 jours après la dernière vérification.502 server_erroravec « no dovecot master credentials » : mailcow n’a pas créé/etc/sogo/sieve.creds; vérifiez que dovecot-mailcow et sogo-mailcow tournent, ou définissez l’utilisateur et le mot de passe master à la main.403 not_allowed: la clé ne couvre pas cette boîte ou n’a pas le droit ; créez une nouvelle clé avec la bonne portée dans la page d’administration.- Aucun webhook n’arrive : vérifiez que le moniteur est actif, que l’adresse est en https et répond en 2xx, et regardez Recent deliveries ; le minuteur s’exécute chaque minute (
systemctl status mlcow-mailapi-<name>.timer). - Aucun ancien courrier après l’ajout d’un moniteur : par conception, le premier passage ne fait qu’enregistrer la position actuelle.
- Gardez Public API address réglé sur votre vraie adresse https ; sinon les liens signés des pièces jointes pointent au mauvais endroit.
- L’API ne crée, ne supprime et ne modifie aucune boîte ; elle travaille uniquement dans les boîtes que vous autorisez. Elle lit le courrier via la connexion master de dovecot à l’intérieur du réseau mailcow, le même mécanisme que mailcow utilise pour imapsync.
Conclusion
L’API d’administration gère le serveur ; ce module gère le courrier, une clé limitée à la fois. Avec une clé read/send/organize par boîte, des webhooks signés vers n8n et un chat Telegram pour les boîtes qui vous importent, vous automatisez votre propre mailcow sans rien céder. Commencez avec une boîte et une clé en lecture seule, confirmez que la vérification de signature du webhook fonctionne, puis élargissez la portée. Le guide utilisateur contient le tableau complet des routes, et le changelog suit les mises à jour ; si quelque chose ne colle pas, la base de connaissances et la FAQ sont les étapes suivantes, ou contactez-nous.