this is a minimal postfix maildir REST API, based on busybox httpd and 75 lines of shell script
Version: 0.3 Date: So 29. Sep 22:18:05 CEST 2024 Author: reinhard@finalmedia.de ## Reading Mailbox (METHOD: GET) ./cgi-bin/v1/get/YOURTOKEN/*/* ............................ listet alle mailbox folders als json ./cgi-bin/v1/get/YOURTOKEN/cur/* .......................... listet alle mails in cur inbox als json ./cgi-bin/v1/get/YOURTOKEN/api/* .......................... listet alle api mail drafts als json ./cgi-bin/v1/get/YOURTOKEN/.foldername/* .................. listet alle mails in given (sub)folder als json ./cgi-bin/v1/get/YOURTOKEN/cur/filename ................... ausgabe der mail, auch dann wenn man zwischenzeitlich flags nach dem : separator modifiziert ./cgi-bin/v1/get/YOURTOKEN/.foldername/filename ........... dito, aber im unterordner ./cgi-bin/v1/get/YOURTOKEN/api/draftfilenumber............. ausgabe des bisherigen geadded draft. es ist auch eine konkatenierbare ausgabe mehrerer drafts nutzbar. ./cgi-bin/v1/get/YOURTOKEN/*/subscriptions ................ ausgabe der imap client subscriptions, also welche abonnierten ordner ./cgi-bin/v1/get/YOURTOKEN/*/dovecot-keywords ............. ausgabe der zuweisung dovecot keywords zur nummer in dateiname ## Adding Data Chunks to mail compose file (METHODE: PUT) ./cgi-bin/v1/add/YOURTOKEN/draftfilenumber/hex_content..... schreibt zeilenweise content in eine vom nutzer hexadezimal benannte draftfile im mailbox Ordner "api". Falls das draftfile verzeichnis api noch nicht existiert, wird es automatisch angelegt. es liegt in der mailbox auf der gleichen ebene wie cur, new und tmp Ein draftfile name darf nur nummerisch(!) sein. z.B. 12345789 Wenn die draftfile datei noch nicht existiert, wird sie angelegt. existiert die datei, wird der gewuenschte content angehaengt. Dabei wird der content in der URL hexadezimal codiert gesetzt und serverseitig decodiert in die datei geschrieben. Beachte: Die Maximale Laenge der gesamten URL wird auf 4096 zeichen begrenzt. Dazu wird auch das "/cgi-bin/v1/add/YOURTOKEN/draftfilenumber/" dazugerechnet. Und die Zeichen sind in hexchars also pro byte jeweils 2 Zeichen. Du musst also z.B. fuer "hello world" mit 22 Zeichen rechnen. und auch ein newline musst du beruecksichtigen, wenn du diesen hinzufuegen willst (0a). ## Completly Remove a compose file line by line (METHODE: DELETE) ./cgi-bin/v1/del/YOURTOKEN/draftfilenumber.................. wenn die draftfile in "api/" existiert, wird sie komplett entfernt. ## Sending composed mailfile (METHODE: POST) ./cgi-bin/v1/send/YOURTOKEN/draftfilenumber................. leitet die draftfile 1:1 an postfix sendmail weiter Wenn der Versand in Ordnung war, wird statuscode 200 und ok geantwortet. Die draftfile/composefile wird nach dem versand nicht entfernt. Man kann sie also bei bedarf bequem mehrfach versenden. um sie zu entfernen ist der del befehl zu benutzen. ### Beispielversand Beispielweise hast du das Token 868e2197fb004325 und möchtest nun einen Mail Text in die neue draftfilenumer 123 adden, anschließend testweise zur Kontrolle auslesen, dann diese Nachricht viermal versenden und das draftfile wieder entfernen. Dann sind dies diese einzelnen Anfragen: " Subject: Ein kleiner Test To: =?UTF-8?Q?J=c3=b6rg_Reinhard?=From: Max Mustermann Date: Mon, 01 Jan 2024 09:00:23 +0100 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8bit Guten Tag! Dies ist ein kleiner öäü Test. " um den text in curl commands umzuwandeln, kann man z.B. diese Pipeline verwenden, dabei waehlen wir eine chunksize von 120 chars als Beispiel: xxd -ps | tr -dc "0-9a-f" | fold -w 120 | sed "s|^|curl -X PUT http://127.0.0.1:5555/cgi-bin/v1/add/868e2197fb004325/123/|g" curl -X PUT http://127.0.0.1:5555/cgi-bin/v1/add/868e2197fb004325/123/5375626a6563743a2045696e206b6c65696e657220546573740a546f3a203d3f5554462d383f513f4a3d63333d623672675f5265696e686172643f3d curl -X PUT http://127.0.0.1:5555/cgi-bin/v1/add/868e2197fb004325/123/203c6578616d706c654066696e616c6d656469612e64653e0a46726f6d3a204d6178204d75737465726d616e6e203c6d61782e6d75737465726d616e curl -X PUT http://127.0.0.1:5555/cgi-bin/v1/add/868e2197fb004325/123/6e4066696e616c6d656469612e64653e0a446174653a204d6f6e2c203031204a616e20323032342030393a30303a3233202b303130300a436f6e7465 curl -X PUT http://127.0.0.1:5555/cgi-bin/v1/add/868e2197fb004325/123/6e742d547970653a20746578742f706c61696e3b20636861727365743d7574662d383b20666f726d61743d666c6f7765640a436f6e74656e742d5472 curl -X PUT http://127.0.0.1:5555/cgi-bin/v1/add/868e2197fb004325/123/616e736665722d456e636f64696e673a20386269740a0a477574656e20546167210a44696573206973742065696e206b6c65696e657220c3b6c3a4c3 curl -X PUT http://127.0.0.1:5555/cgi-bin/v1/add/868e2197fb004325/123/bc20546573742e0a0a curl -X GET http://127.0.0.1:5555/cgi-bin/v1/get/868e2197fb004325/api/123 curl -X POST http://127.0.0.1:5555/cgi-bin/v1/send/868e2197fb004325/123 curl -X POST http://127.0.0.1:5555/cgi-bin/v1/send/868e2197fb004325/123 curl -X POST http://127.0.0.1:5555/cgi-bin/v1/send/868e2197fb004325/123 curl -X POST http://127.0.0.1:5555/cgi-bin/v1/send/868e2197fb004325/123 curl -X DELETE http://127.0.0.1:5555/cgi-bin/v1/del/868e2197fb004325/123 ### Konkatenierung und Autocomplete des filename bei einem read request Um mehrere Mails auf einmal auszugeben (konkateniert), kannst du als dateiname einen range verwenden. Wenn du also die liste abfragst, erhältst du ja einen json array in dem z.B. solche Dateinamen zurückgeliefert werden _____ timestamp / _______ ID ___ info _____ flags | / / / | | | | 1668668756.M289355P3876294.mail,S=3656,W=3721:2,Sa Die normalen Dateinamen von mails in einer maildir beginnen also mit einem unixtimestamp. Wichtig: Wenn du eine Mail abfragst, frage normalerweise auf einen Dateinamen vor dem Doppelpunkt Frage also auf 1668668756.M289355P3876294.mail und du bekommst die passende mail als ausgabe. Hintergrund ist.. wenn jemand anderes parallel per imap Änderungen vornimmt, werden sich Werte nach dem : am dateinamen ändern. 2 ist z.b. eine "gelesene" mail. Da du evtl. die Liste aber vorher abgefragt hast, würdest du dann keine gelesene mail mehr unter dem namen finden. referenziere daher bei deiner Abfrage 1668668756.M289355P3876294.mail. Das System ist aber flexibel. Du kannst auch den vollen Namen 1668668756.M289355P3876294.mail,S=3656,W=3721:2,Sa anfragen, oder sogar nur 1668668756.M289355P387 wenn es sonst keine weitere mails mit diesem beginnenden Dateinamen gibt. Gibt es mehrere Dateien nach dem angefragten Schema, werden diese automatisch **konkateniert** zurückgeliefert. Konkret: Du musst also nicht den vollen filename eingeben, sondern z.b. nur den anfang. Beispiel: http://127.0.0.1:5555/cgi-bin/v1/get/YOURTOKEN/cur/172 Das gibt dir aus der aktuellen Hauptordner alle Mails aus, deren Dateiname mit 172 beginnt, also unix timestamp 172, folglich 1720000000.. und damit alle Mails ab Mi 3. Jul 11:46:40 CEST 2024 Tipp: Du kannst mit date -d @1720000000 ausgeben lassen, welche unix timestamps, welchem datum entsprechen. Um also z.B. aus einer Mailbox alle Emails konkateniert auszugeben, kannst du sogar das hier verwenden http://127.0.0.1:5555/cgi-bin/v1/get/YOURTOKEN/cur/1 solange also deren unix-timestamp mit 1 beginnt. ## Was sind Tokens? Token Erzeugung auf dem Mailserver wenn du deine postfix mails z.B. alle in der maildir /var/vmail/domain/usermailboxname liegen hast, dann erstellst du erstmal ein zentrales tokenverzeichnis: mkdir /etc/apitokens/ chown vmail:vmail /etc/apitokens chmod u=rx,g=rx,o= /etc/apitokens und dort dann symlinks zu einer mailbox erstellen. die symlinks dabei kryptischen benennen. das sind die tokens. beispiel: fuer ein token 868e2197fb004325 machst du als root user ln -sf /var/vmail/domain/usermailbox/ /etc/apitokens/868e2197fb004325 damit ist alles fertig. beachte. ein token MUSS hexadezimal ascii sein. Also nur Zeichen 0123456789abcdef erlaubt. Nichts anderes! Du machst das für alle mailboxen, die du auch auf diese weise exponieren willst. jede mailbox bekommt dabei ein von dir definiertes zufallstoken. Aus sicherheitsgründen sollte dieses token mindestens 16 zeichen lang sein, besser mehr. ### Wie nutze ich das nun auf serverseite? du startest den service dann z.B. als root mit exec env -i busybox httpd -u vmail:vmail -f -p 127.0.0.1:5555 -h minimail/ -vv und kannst das z.B: mit den daemontools tun. busybox httpd bindet dann loopback an den port 5555 und dropped dann aber direkt seine priviledges zum angegeben user vmail und gruppe vmail. alle scripte aus cgi-bin laufen also mit den Rechten von vmail:vmail. und es werden lese und schreibrechte im via /etc/apitokens/ versymlinkten zielverzeichnis (also der mailbox) benötigt. ### Begriffserklärungen #### API An Application Programming Interface is an interface exposed by a program, part of an operating system or programming language to other programs, so that the programs that use the API can exploit the features of the program that exposes the API. APIs are only used by programs, they are not user interfaces.