minimail

this is a minimal postfix maildir REST API, based on busybox httpd and 75 lines of shell script

Reference Guide

 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.