Für KI-Agenten
`openemail` aus Claude Code, Codex oder einem CI-Job steuern: unbeaufsichtigte Anmeldung, Hilfe als Daten, Probeläufe, fehlende Scopes und Bestätigungscodes.
Die eingebaute Anleitung
openemail agents gibt eine kurze Anleitung in Markdown für einen KI-Agenten wie Claude Code oder Codex oder für ein Skript in CI aus: wie man sich ohne einen Menschen anmeldet, die Ausgabe liest, Befehle findet, Dinge sicher ändert und durch Listen blättert, was zu tun ist, wenn ein Bestätigungscode oder ein Scope fehlt, und fünf Rezepte zum Kopieren. openemail agent ist derselbe Befehl.
openemail agentsopenemail agents --json | jq -r '.recipes[].commands[]'Mit --json ist die Anleitung ein Dokument mit schemaVersion, title, intro, sections aus { id, title, points }, exitCodes und recipes aus { id, title, commands }. Statt diese Regeln in jeden Prompt zu kopieren, sagen Sie dem Agenten einmal, in der Anweisungsdatei, die Ihr Projekt ihm ohnehin gibt, dass er openemail agents ausführen soll, bevor er die CLI nutzt.
Anmelden ohne einen Menschen
- Nutzen Sie einen API-Schlüssel. Setzen Sie
OPENEMAIL_API_KEYoder übergeben Sie--api-keyan einen einzelnen Befehl. Erstellen Sie ihn unter Einstellungen → API-Schlüssel (openemail open api-keys) mit nur den Scopes, die der Agent braucht. Ein Schlüssel öffnet nie einen Browser und braucht nie einen Bestätigungscode. - Oder verwenden Sie eine Browser-Anmeldung weiter, die ein Mensch einmal auf diesem Rechner mit
openemail loginvorgenommen hat, und wählen Sie sie mit--profile <name>. Die CLI erneuert ihre Tokens selbst. - Ohne Terminal fragt nichts nach. Unter
--json,--no-inputoderCI, oder ohne angeschlossenes Terminal, bricht ein Wert, nach dem die CLI gefragt hätte, mit Exit-Code2ab und nennt das Flag, das zu übergeben ist. - Eine Browser-Anmeldung braucht einen Menschen, der sie freigibt, daher bricht ein unbeaufsichtigtes
openemail loginmit Exit-Code2und dem Codeunattendedab, bevor es irgendetwas registriert, und verweist aufopenemail login --with-token. openemail whoami --jsonzeigt den Workspace, die Art der Anmeldung und ihrescopes.
Die Ausgabe lesen
Übergeben Sie --json an jeden Befehl. stdout enthält dann genau ein JSON-Dokument, oder ein Objekt pro Zeile mit --ndjson, und der Fortschritt bleibt auf stderr. Ein Fehler gibt eine {"error":{...}}-Zeile auf stderr aus: Verzweigen Sie nach dem Exit-Code und nach dessen code, zeigen Sie next einem Menschen, und parsen Sie nie message, dessen Wortlaut sich ändern kann. Die Seite „Skripte“ führt jedes Feld und jeden Exit-Code auf.
Befehle als Daten
--help --json gibt die Hilfe als ein JSON-Dokument aus, gebaut aus derselben Befehlsregistrierung, mit der die CLI parst, sodass sie immer zur installierten Version passt. Es funktioniert auf der obersten Ebene, bei einer Gruppe oder einem Befehl, und openemail help <command> --json gibt dasselbe aus.
openemail send --help --jsonopenemail domains delete --help --json | jq '.commands[0] | {scopes, destructive}'openemail help domains --json | jq -r '.commands[0].subcommands[].command'openemail --help --json | jq -r '.commands[].command'Das Dokument
schemaVersionnumber- Ändert sich, wenn ein Feld seine Bedeutung ändert
cli, versionstring- Immer `openemail`, und die Version, die es ausgegeben hat
pathstring[]- Der abgefragte Befehl, leer für die oberste Ebene
commandsobject[]- Für die oberste Ebene jeder Befehl der ersten Ebene, sonst der abgefragte, jeweils mit seinen Unterbefehlen
globalFlagsobject[]- Die Flags, die jeder Befehl annimmt, in derselben Form wie die Flags eines Befehls
subcommandAliasesobject- Jeder gemeinsame Alias wie `ls` oder `rm` und die Verben, für die er steht
exitCodesobject[]- Jeder Exit-Code als `{ code, name, meaning }`
Ein Befehl
namestring- Das letzte Wort des Befehls
commandstring- Der ganze Befehl, zum Beispiel `openemail domains delete`
path, aliasesstring[]- Die Wörter nach `openemail`, die zu ihm führen, und seine anderen Namen
summary, descriptionstring- Was er tut, in einer Zeile und ausführlich
usagestring[]- Wie er aufgerufen wird
categorystring | null- Sein Abschnitt in `openemail --help` bei einem Befehl der ersten Ebene, sonst `null`
group, runnable, hiddenboolean- Ob er Unterbefehle hat, ob er für sich allein läuft und ob die Hilfe ihn auslässt
authstring- Die Anmeldung, die er braucht: `required`, `browser` nur für eine Browser-Anmeldung, `optional` oder `none`
scopesstring[]- Die API-Scopes, die jeder seiner Aufrufe braucht
destructiveboolean- Ob er zuerst um Bestätigung bittet, die `--yes` erteilt
argumentsobject[]- `name`, `description`, `required` und `variadic` jedes Arguments
flagsobject[]- `name`, `short`, `kind`, `required`, `repeatable`, `choices`, `placeholder`, `description` und `hidden` jedes Flags
notes, examplesobject[]- Die zusätzlichen Hilfeblöcke als `{ title, lines }` und die Beispiele als `{ command, note }`
resourceobject | null- Bei einem Ressourcenbefehl die SDK-Methode und der REST-Aufruf dahinter, sonst `null`
subcommandsobject[]- Die Befehle unter einer Gruppe, in derselben Form
Eine Ressource
namespacestring- Der SDK-Namespace, zum Beispiel `domains`
sdkMethodstring- Die SDK-Methode, zum Beispiel `openemail.domains.delete`
sdkMethodAllstring | null- Bei einer Liste die `listAll`-Methode, die `--all --json` durchläuft
httpMethod, httpPathstring- Der REST-Aufruf, zum Beispiel `DELETE` und `/domains/{id}`
scopesstring[]- Die Scopes, die die Methode braucht
authstring- `apiKey`, oder `none` und `inboxToken` für eine Methode, die keinen API-Schlüssel sendet
returnsobject- `{ shape, type }`: die Form der Antwort, zum Beispiel `object` oder `page`, und ihr SDK-Typ
paginatesboolean- Ob sie eine Seite einer Liste zurückgibt
Der ganze Baum ist etwa ein Megabyte groß, fast alles davon die 198 Ressourcenbefehle, fragen Sie also nach dem Befehl, den Sie brauchen, oder filtern Sie den Baum mit jq. Der Text behält seine Backticks und enthält keine Farbcodes, und versteckte Befehle wie security sind enthalten, mit hidden auf true.
Probeläufe
--dry-run funktioniert bei jedem Befehl außer mcp serve. Lesezugriffe laufen wie gewohnt, dann wird die erste Anfrage, die etwas ändern würde, ausgegeben statt gesendet, und der Befehl endet mit Exit-Code 0, ohne sonst etwas zu tun. Bestätigungen werden übersprungen, da nichts gesendet wird, sodass ein Agent sehen kann, was ein destruktiver Befehl tun würde, ohne --yes zu übergeben.
openemail domains delete <domain-id> --dry-runopenemail send --from [email protected] --to [email protected] --subject "Hi" --text "Hello" --dry-run --json{ "dryRun": true, "request": { "method": "POST", "url": "https://api.openemail.uk/emails", "headers": { "accept": "application/json", "authorization": "Bearer [redacted]", "content-type": "application/json", "idempotency-key": "58e6fb61-ad2e-401e-b141-7a0546c7c749", "user-agent": "openemail-cli/0.0.1 openemail-sdk/0.0.5" }, "body": { "from": "[email protected]", "to": [ "[email protected]" ], "subject": "Hi", "text": "Hello" }, "raw": null }}- Eine Änderung ist jede Anfrage außer
GETundHEAD, ein MCP-Tool-Aufruf sowie die An- und Abmeldeanfragen vonloginundlogout. Die Token-Erneuerung unddocs asklaufen trotzdem. - Der Plan zeigt die Methode, die vollständige URL, die Header mit dem Wert von
Authorizationgekürzt aufBearer [redacted]und den JSON-Body, in dem geheime Felder wie ein Resend-Schlüssel geschwärzt sind. Ein Upload zeigt nur seine Größe und seinen Inhaltstyp. - Eine Änderung, die auf diesem Rechner bleibt, wie
profile use,login --with-tokenoder das Vergessen eines gespeicherten API-Schlüssels, gibt{"dryRun":true,"local":{"action","profile"}}aus und speichert nichts. - Ein Befehl, der vor seiner ersten Änderung ausgibt, was er gelesen hat, zeigt das zuerst:
readgibt den Thread aus, dann die Anfrage, die ihn als gelesen markieren würde. Übergeben Sie--no-mark-read, um die zweite wegzulassen. mcp servelehnt--dry-runmit Exit-Code2ab, weil sein Client entscheidet, was gesendet wird. Prüfen Sie stattdessen einen einzelnen Tool-Aufruf mitopenemail mcp call <tool> --dry-runvorab.
Fehlende Scopes
Jeder Befehl kennt die API-Scopes, die er immer braucht, und seine Hilfe führt sie auf. Fehlt einer gespeicherten Anmeldung einer davon, fragt der Befehl die API einmal nach der aktuellen Liste, sodass Zugriff, der nach der Anmeldung auf der Website erteilt wurde, sofort zählt. Fehlt der Scope dann immer noch, bricht er mit Exit-Code 4 und dem Code insufficient_scope ab, bevor er etwas fragt oder eine Anfrage sendet:
{"error":{"type":"cli_error","code":"insufficient_scope","message":"This sign-in does not have the emails:send permission, which openemail send needs.","hint":null,"next":"Give this app more access in Account settings, Connected apps (openemail open apps, then Edit access), or run openemail login --force and choose more access.","status":null,"requestId":null,"param":null,"docUrl":null,"exitCode":4}}- Bei einer Browser-Anmeldung sagt
next, dass Sie der App unter Konto → Kommandozeile mehr Zugriff geben (openemail open cli, dann Zugriff bearbeiten) oderopenemail login --forceausführen und mehr Zugriff wählen sollen. Eine Browser-Anmeldung erhält niekeys:writeoderkeys:manage, daher verweist sie dafür auf einen API-Schlüssel. - Bei einem API-Schlüssel sagt
next, dass Sie einen Schlüssel mit diesem Scope verwenden sollen. - Ein Schlüssel aus
--api-keyoderOPENEMAIL_API_KEYwird nicht vorab geprüft, und die API entscheidet. Lehnt die API einen Aufruf wegen eines fehlenden Scopes ab, trägt der Fehler dasselbenext.
Bestätigungscodes
Ein API-Schlüssel braucht nie einen Bestätigungscode. Eine Browser-Anmeldung braucht einen vor einer heiklen Änderung, etwa beim Hinzufügen eines Webhooks, beim Anlegen einer Regel, beim Ändern eines Mitglieds oder beim Entfernen einer Domain, und ein Agent kann ihn nicht eingeben. Bevor der Agent läuft, führt daher ein Mensch entweder openemail verify in einem Terminal mit demselben Profil aus oder wählt Änderungen für 60 Minuten erlauben für diese Anmeldung unter Konto → Kommandozeile. Beides deckt die nächsten 60 Minuten ab.
openemail verifyopenemail verify --status --jsonverify --status --json sagt dem Agenten, ob das Profil bestätigt ist, in elevated, und bis wann, in elevatedUntil. Ohne Bestätigung bricht die Änderung mit Exit-Code 4 und dem Code step_up_required ab, und nichts wird geändert:
{"error":{"type":"cli_error","code":"step_up_required","message":"This action needs a verification code, and there is no interactive terminal to ask for one.","hint":null,"next":"Run openemail verify in an interactive terminal first, then run this again within 60 minutes. An API key never needs a code.","status":403,"requestId":"req_9Qm4tV","param":null,"docUrl":"https://openemail.uk/docs/api/errors#step_up_required","exitCode":4}}Über MCP
Ein Agent, der MCP spricht, kann stattdessen den OpenEmail-MCP-Server nutzen. openemail mcp config --client claude-code, oder codex, cursor und die anderen Clients, die es auflistet, gibt die Einrichtung aus, und openemail mcp serve ist eine lokale Brücke, die die Browser-Anmeldung dieser CLI wiederverwendet. API-Schlüssel erreichen den MCP-Server nicht. Die Seite „KI und MCP“ hat die Einzelheiten.
Rezepte
openemail inbox --unread --limit 20 --jsonopenemail inbox --unread --json | jq -r '.items[].id'openemail read CAHk7pQ2x9LmZ4 --no-mark-read --jsonopenemail send --from [email protected] --to [email protected] --subject "Weekly report" --body-file report.md --idempotency-key weekly-report-39 --jsonopenemail domains create --domain example.com --dry-run --jsonopenemail domains create --domain example.com --jsonopenemail whoami --json | jq '.scopes'