En opskrift til en kodeagent
Hvis du vil skrive programmet selv
MailFetcher er et afgrænset program: læs mail fra IMAP, gem den komplette meddelelse som en lokal EML-fil, og rør ikke ved mailen på serveren.
Her er specifikationen, hvis du hellere vil bygge det selv. Den beskriver programmet og dets stopkriterier på én side. Vælg selv sprog og biblioteker, så længe adfærden nedenfor er den samme.
1. Opgaven
- Byg et selvstændigt kommandolinjeprogram til Linux, macOS og Windows. Det skal kunne køre én hentning og afslutte eller blive ved med at kontrollere flere konti med hvert sit interval.
- Hver konfigureret IMAP-mappe knyttes til én absolut lokal destinationsmappe. Første kørsel henter alle eksisterende mails, medmindre en positiv batchgrænse er sat. Senere kørsler henter kun nye UID'er.
- Gem serverens rå RFC 5322/MIME-meddelelse uændret som
.eml, inklusive headers, multipart-dele og vedhæftninger. Programmet skal ikke rendere, normalisere eller udtrække indhold. - Programmet må aldrig sende, markere som læst, flytte eller slette mail på serveren. Lokal efterbehandling af EML-filer er uden forbindelse til IMAP-serveren.
2. Konfiguration og kommandoer
Indlæs én privat JSON-fil via --config. Afvis ukendte felter, dublerede konto-ID'er, relative stier, ugyldige intervaller og manglende legitimationsoplysninger. På Unix må konfigurationsfilen ikke kunne læses af gruppe eller andre; tilstandsmappe og destinationsmapper skal oprettes privat. Læg aldrig hemmeligheder i repository eller log.
{
"state_dir": "/home/user/.local/state/mailfetcher",
"accounts": [{
"id": "work",
"host": "imap.example.com",
"port": 993,
"tls": "implicit",
"username": "user@example.com",
"auth": "password",
"password": "APP_PASSWORD",
"poll_interval": "5m",
"batch_size": 0,
"folders": [{"remote": "INBOX", "destination": "/home/user/Mail/work"}]
}]
}
Konto-ID må kun indeholde bogstaver, tal, understregning og bindestreg. poll_interval skal være mindst ét minut. batch_size: 0 betyder ingen grænse. TLS kan være implicit TLS eller STARTTLS; login må først ske efter verificeret TLS. Tillad eventuelt en eksplicit PEM-CA-fil til private servere, men slå aldrig certifikatkontrol fra.
Implementér run --config PATH --once, run --config PATH og authorize --config PATH --account ID. --once skal forsøge alle konti og returnere fejlstatus, hvis mindst én fejler. Vedvarende drift skal respektere hvert konto-interval og kunne stoppes rent med SIGINT/SIGTERM. Kun én proces må eje samme tilstandsmappe ad gangen.
3. Forbindelse og IMAP-læsning
- Understøt password-login og Gmail OAuth 2.0 via XOAUTH2. Gmail-varianten skal bruge
imap.gmail.com:993og implicit TLS. Autorisationen bruger en desktop-klient, browsergodkendelse og en lokal loopback-callback. Gem refresh token privat, hent nyt access token ved behov, og kræv ny autorisation ved tilbagekaldt grant. IMAP med Gmail kræver scopehttps://mail.google.com/. - Åbn hver mappe med IMAP
EXAMINE, aldrigSELECTi skrivbar tilstand. Kræv et gyldigtUIDVALIDITY. Find UID'er medUID SEARCH ALL; sortér dem numerisk og behandl dem i stigende rækkefølge. - Hent en mail med
UID FETCH <uid> (UID BODY.PEEK[]). Verificér, at svaret gælder det ønskede UID, kun indeholder én meddelelseskrop, og at den læste længde svarer til IMAP-literalens oplyste længde. Håndtér quoted mailbox-navne og IMAPs modified UTF-7 korrekt. - Afvis et ufuldstændigt, uventet eller fejlbehæftet serversvar. Luk forbindelsen og lad næste kørsel genoptage fra den sidst færdige mail.
4. Filer, identitet og fremdrift
Identificér en mail med konto-ID, fjernmappens navn, UIDVALIDITY og UID. Lav deterministiske filnavne med disse værdier, så to mapper og to konti ikke kolliderer. Brug eventuelt et kort hash af mappenavnet i filnavnet. En lokalt slettet færdig fil skal ikke automatisk hentes igen, når dens UID allerede er registreret som færdig.
Skriv først til en midlertidig .partial-fil i destinationsmappen. Kontrollér antal bytes, flush filen til disk, luk den og omdøb den atomisk til .eml. Opdatér først derefter den private fremdriftsfil atomisk med seneste færdige UID. Afbrydes processen før omdøbning eller fremdriftsskrivning, må næste kørsel kunne gentage uden at efterlade en halv EML-fil som færdigt resultat.
Gem fremdrift pr. konto og mappe som UIDVALIDITY og seneste færdige UID. Hvis serveren ændrer UIDVALIDITY, starter en ny UID-sekvens; den gamle UID må aldrig tolkes som identitet i den nye sekvens. En batchgrænse gælder pr. mappe pr. kørsel.
5. Drift og fejl
Log konto-ID, mappenavn, antal fundne og hentede mails, seneste UID og næste kontroltidspunkt. Log sikre fejl uden passwords, OAuth-tokens, IMAP-kommandoer med legitimationsoplysninger eller mailindhold. Én kontos fejl må ikke forhindre forsøg på de andre konti. Brug forbindelses- og læsetimeouts, og lad fejl give en ny prøve ved næste interval frem for at springe en UID over.
Det lokale arkiv og tilstanden er separate data. En flytning til en ny computer skal omfatte begge dele eller en bevidst ny fuld hentning. Programmet må ikke afhænge af en MailFetcher-webservice.
6. Det skal kunne bevises
- En test-IMAP-server ser kun
EXAMINE,UID SEARCHogBODY.PEEK[]ved hentning. Serverens læst-flag og mappeindhold forbliver uændret. - En mail med MIME-vedhæftning er byte-for-byte identisk med den hentede EML-fil. En afbrudt literal efterlader ingen færdig fil og flytter ikke fremdriften.
- Gentaget kørsel giver ingen dubletter. Genstart efter en halv batch fortsætter fra sidste færdige UID. Ny
UIDVALIDITYbehandles som en ny sekvens. - Forkert TLS-certifikat, udløbet OAuth-grant, ugyldig konfiguration og en ulæselig tilstandsfil stopper sikkert med en forståelig fejl. Ingen hemmeligheder står i loggen.