Mailkoppelingen via de API¶
Het concept achter tools staat in Tools.
Een mailkoppeling geeft het model toegang tot één mailbox: zoeken, lezen, markeren,
verplaatsen, een concept opslaan en, als je dat toestaat, versturen. Core leest de mailbox over
IMAP en verstuurt over SMTP, via de mailservers van je organisatie en met haar eigen login. Een
koppeling opent de mailbox van je organisatie, zoals support@, of per aanroep de eigen mailbox
van de persoon voor wie de beurt is. Een koppeling kan ook nieuwe mail opmerken en daarmee een
workflow starten.
Een mailkoppeling stel je in via de API, zoals hieronder, of in de console onder Tools >
Mailkoppelingen. Daar voeg je er een toe op een eigen pagina, zie je de servers, mappen en
verzendgrenzen van een koppeling en of het volgen van nieuwe mail werkt, bewerk je hem tot een
nieuwe versie, verwijder je hem, en laat je Core met Testen inloggen op de IMAP-server, en ook
op de SMTP-server als de koppeling verstuurt. Bij een mailbox per persoon zie je op de pagina van de
koppeling of je je eigen mailbox hebt verbonden, met Verbind je account en Verbinding
verbreken; Testen meldt bij zo'n mailbox dat inloggen is geweigerd, omdat er bij een test geen
persoon is om als in te loggen. Geheimen zie je nooit terug. Je sleutel heeft de
capability tooling nodig, en de hosts van de IMAP- en SMTP-server moeten bij de toegestane
hosts van je organisatie staan.
Een mailbox van de organisatie koppelen¶
curl -s -X POST "$CORE_URL/mail_connectors" \
-H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
-d '{"name": "support",
"description": "De supportmailbox van Acme. Klanten mailen hier hun vragen.",
"imap": {"host": "imap.acme.example", "port": 993, "security": "implicit_tls"},
"smtp": {"host": "smtp.acme.example", "port": 587, "security": "starttls"},
"folders": ["INBOX", "Afgehandeld"],
"drafts_folder": "Drafts",
"from_address": "support@acme.example",
"send_allowed_domains": ["acme.example", "klant.example"],
"auth": {"type": "basic", "username": "support@acme.example", "password": "..."}}'
Het antwoord is 201 met de koppeling, versie 1. tools op het antwoord noemt de tools die deze
versie aanbiedt.
| Veld | Wat je invult |
|---|---|
name |
kleine letters, cijfers, - en _, maximaal 48 tekens; de tools heten mail__<name>__<operatie>. Wijzigt na aanmaken niet meer |
description |
waar deze mailbox voor is; het model leest het boven de beschrijving van elke tool |
imap |
{host, port, security} van de server waarmee de tools lezen |
smtp |
dezelfde vorm, voor versturen; laat weg om niet te versturen |
folders |
de mappen die de tools mogen gebruiken, standaard ["INBOX"]; de eerste is de map als een tool er geen noemt. Een mapnaam bestaat uit leesbare ASCII-tekens |
drafts_folder |
de map voor concepten; laat weg om geen concepttool aan te bieden |
from_address |
de afzender van elk verstuurd bericht en elk concept; het model kiest die nooit |
send_allowed_domains |
de domeinen waarnaar versturen mag, precies zoals geschreven; leeg betekent niet versturen |
max_recipients |
hoogstens zoveel to en cc per bericht, standaard 10, hoogstens 50 |
sends_per_hour |
hoogstens zoveel berichten per klokuur, standaard 20, hoogstens 1.000 |
auth |
hoe Core inlogt, zie Inloggen |
mailbox |
de mailbox die een applicatietoken opent; alleen bij oauth_client_credentials |
ca_pem |
de certificaatautoriteit van je eigen servers, als PEM; laat weg voor de publieke autoriteiten |
region |
waar de servers draaien, zoals bij een API-koppeling |
watch |
nieuwe mail opmerken in één map, zie Nieuwe mail |
security is implicit_tls (IMAP 993, SMTP 465) of starttls (IMAP 143, SMTP 587). Een
verbinding zonder versleuteling bestaat niet, en het certificaat moet altijd de naam van de host
dragen.
GET /mail_connectors toont de koppelingen van je organisatie, GET /mail_connectors/{id} er één,
PATCH wijzigt er een en DELETE verwijdert er een, met elk bericht dat nog niet verstuurd is en
de toestemming van elke persoon.
Verwijderen geeft 409 met de namen van de agents zolang de nieuwste versie van een agent een van
de tools noemt.
Inloggen¶
auth is een van drie soorten. Het geheim wordt versleuteld opgeslagen en nooit teruggegeven.
auth.type |
Velden | Wat Core doet |
|---|---|---|
basic |
username, password |
logt met dezelfde gegevens in bij IMAP en SMTP |
oauth_client_credentials |
token_url, client_id, client_secret, scopes, audience |
haalt een token van de applicatie op en opent daarmee de mailbox in mailbox, bijvoorbeeld een gedeelde mailbox in Microsoft 365 |
oauth_authorization_code |
authorize_url, token_url, client_id, client_secret (optioneel), scopes, audience; of client, de naam van een OAuth-applicatie die je operator instelde, in plaats van de eerste vier |
opent per aanroep de eigen mailbox van de persoon, zie De mailbox van een persoon |
mailbox is verplicht bij oauth_client_credentials en wordt bij de andere twee geweigerd. Het
token-endpoint moet net als de servers bij je toegestane hosts staan.
De mailbox van een persoon¶
Met oauth_authorization_code heeft elke persoon een eigen mailbox achter dezelfde tools. Een
aanroep logt in als de persoon voor wie de beurt is, dus twee mensen die dezelfde tool gebruiken,
lezen twee verschillende mailboxen en zien elkaars mail nooit.
-
Registreer de koppeling met de gegevens van je provider. Vraag naast de scope voor IMAP ook
openidenemail: Core leest het adres van de mailbox uit het ID-token dat de provider bij het inloggen teruggeeft.curl -s -X POST "$CORE_URL/mail_connectors" \ -H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \ -d '{"name": "inbox", "description": "De eigen mailbox van de persoon voor wie je werkt.", "imap": {"host": "imap.provider.example", "port": 993, "security": "implicit_tls"}, "auth": {"type": "oauth_authorization_code", "authorize_url": "https://id.provider.example/authorize", "token_url": "https://id.provider.example/token", "client_id": "artific-core", "scopes": ["openid", "email", "<de IMAP-scope van je provider>"]}}' -
Registreer
<de publieke basis-URL van Core>/api/v1/oauth/callbackals redirect-URI bij je provider. -
Noem de persoon met
userop elk verzoek, en vraag de persoon in te loggen. Dat werkt precies als bij een API-koppeling (De persoon logt zelf in), met dezelfde routes onder/mail_connectors/{id}/authorizations:curl -s -X POST "$CORE_URL/mail_connectors/mail_01J.../authorizations" \ -H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \ -d '{"user": "u_9f31", "return_url": "https://jouw-app.example/instellingen"}'Geef de
urluit het antwoord aan de persoon.GET .../authorizations/{user}zegt of Core haar toestemming heeft, enDELETE .../authorizations/{user}vergeet die.
Bij het inloggen bewaart Core het adres dat de provider in het ID-token noemt, versleuteld bij de
toestemming. Zegt de provider dat het adres niet geverifieerd is, dan wordt er geen mailbox
gekoppeld en leest de persoon Your sign-in did not confirm a verified email address, so no
mailbox was connected., of komt ze terug op je return_url met authorization=denied. De
mailserver controleert het adres tegen het token, dus een persoon opent nooit een mailbox die ze
zelf niet al kon openen.
Zo'n mailbox heeft geen persoon achter werk dat buiten een beurt draait. Daarom wordt hij nooit
voor zichzelf bewaakt en verstuurt hij nooit voor een persoon; een concept opslaan kan wel. De enige
uitzondering is de eigen mailbox van een serviceaccount. Als het beheer de koppeling als mailbox
van het account noemt, bewaakt mail_watch hem op nieuwe mail met de watch van de versie, elk
nieuw bericht een mail.received-gebeurtenis van het account met service_account; met
mail_send versturen de beurten van het account via die koppeling onder de verzendregels van de
versie, en leest elke andere beurt This mailbox sends only for its service account. De
authorizations-routes geven 409 bij een koppeling van een andere soort.
De tools¶
Welke tools een versie aanbiedt, volgt uit wat ze instelt. Elke map die een tool mag noemen, is een
keuze uit folders.
| Tool | Aangeboden als | Wat hij doet |
|---|---|---|
mail__<naam>__search |
altijd | zoekt in één map op from, to, subject, since, before en unseen; geeft de nieuwste treffers, standaard 20 en hoogstens 50, elk met zijn uid, afzender, ontvangers, onderwerp, datum en of het gelezen of gemarkeerd is |
mail__<naam>__read |
altijd | leest één bericht op uid: de headers, de tekst (tot 32 KiB) en de bijlagen, die als artefacten worden bewaard. Een bericht groter dan 25 MiB wordt niet opgehaald |
mail__<naam>__mark |
altijd | zet of wist gelezen (seen) en gemarkeerd (flagged) op één bericht |
mail__<naam>__move |
folders noemt minstens twee mappen |
verplaatst één bericht naar een andere toegestane map |
mail__<naam>__draft |
een drafts_folder en een from_address |
slaat een bericht in platte tekst op als concept, zodat een persoon het nakijkt en verstuurt |
mail__<naam>__send |
een smtp, een from_address en minstens één domein in send_allowed_domains |
verstuurt een bericht in platte tekst, zie Versturen |
Zoeken en lezen markeren nooit iets als gelezen. Een concept en een bericht nemen to, cc,
subject en body, en met reply_to_uid een antwoord op een bericht, met de headers die een
antwoord bij dat bericht houden.
Bied de tools aan op naam, {"type": "tool", "name": "mail__support__search"}, of allemaal tegelijk
met een toolset met het patroon mail__support__*.
Versturen¶
Alles wat een bericht kan tegenhouden, beslist Core terwijl het model wacht: elke ontvanger is één
adres in precies een van de send_allowed_domains, er zijn er hoogstens max_recipients, de
SMTP-host is toegestaan, en het bericht krijgt een van de sends_per_hour plaatsen van dit
klokuur.
Daarna leest het model The mail is queued and will be sent. Het bericht wordt verstuurd nadat
de beurt is afgerond; een beurt die daarna mislukt, verstuurt niets. Een plaats in het uur die zo'n
beurt al nam, blijft wel gebruikt. Core probeert opnieuw zolang de server onbereikbaar is of een
tijdelijke fout geeft; elke poging draagt dezelfde Message-ID, zodat een herhaling als hetzelfde
bericht te herkennen is. Weigert de server het bericht definitief, dan probeert Core het niet
opnieuw.
Hoe het afliep, staat in het auditspoor: mail_connector.mail_sent,
mail_connector.mail_refused of mail_connector.mail_dropped, met id's en zonder adressen of
tekst. Hoe het ook afloopt, daarna bewaart Core de tekst van het bericht niet langer.
Nieuwe mail¶
Stel watch in om nieuwe mail in één map op te merken:
curl -s -X PATCH "$CORE_URL/mail_connectors/mail_01J..." \
-H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
-d '{"watch": {"folder": "INBOX", "poll_seconds": 300}}'
| Veld | Wat het is |
|---|---|
folder |
de map die Core bewaakt; een van folders |
poll_seconds |
hoe vaak Core naar nieuwe mail vraagt, standaard 300, minstens 60 tenzij je operator een andere ondergrens instelde, hoogstens 86.400 (een dag) |
enabled |
of Core de map bewaakt, standaard true |
Elk nieuw bericht in die map wordt één gebeurtenis mail.received, met het id van de koppeling in
mail_connector, de folder en de uid, en nooit een adres, een onderwerp of een tekst. Mail die
al in de map stond toen het bewaken begon, telt niet als nieuw. Eén keer kijken meldt hoogstens 100
nieuwe berichten, oudste eerst; de rest volgt de volgende keer. Hoe je daarmee een workflow start,
staat in Nieuwe mail.
Een read van de koppeling toont hoe het bewaken gaat:
watch_status |
Betekenis |
|---|---|
pending |
Core heeft de map nog niet gelezen |
ok |
de laatste keer lukte het |
denied |
de host of zijn adres is niet toegestaan |
auth_failed |
de server weigerde de login |
unreachable |
de server antwoordde niet |
refused |
de server weigerde de map |
watch_polled_at zegt wanneer Core het laatst keek. Na een mislukking wacht Core steeds langer,
tot een uur, voor het opnieuw probeert. {"watch": null} stopt het bewaken. Een andere map kiezen
begint opnieuw: Core telt dan pas mail die daarna binnenkomt.
Een koppeling testen¶
POST /mail_connectors/{id}/test logt in bij de IMAP-server en opent de eerste map alleen om te
lezen, en logt bij een koppeling die verstuurt ook in bij de SMTP-server. Er wordt niets opgeslagen
en niets verstuurd.
{"imap": {"ok": true, "code": "ok"}, "smtp": {"ok": false, "code": "auth_failed"}}
code is ok, denied (de host of zijn adres is niet toegestaan), unreachable, auth_failed
of refused; smtp is null bij een koppeling die niet verstuurt. Een mailbox van een persoon
heeft bij de test geen persoon, en antwoordt daarom auth_failed voor IMAP.
Versies¶
Een koppeling is geversioneerd. Een PATCH die wijzigt wat de koppeling doet, maakt een nieuwe
versie; een PATCH van alleen auth, mailbox of region maakt er geen. Met een expliciete
null zet je een tool uit: smtp, from_address of "send_allowed_domains": [] stopt het
versturen, en drafts_folder of from_address het concept.
GET /mail_connectors/{id}/versions toont de versies, nieuwste eerst (?order=asc voor oudste eerst), en
GET /mail_connectors/{id}/versions/{version} er één. Pin een versie zoals bij elke koppeling:
{"type": "tool", "name": "mail__support__read", "version": 2} (Een versie
vastpinnen).
Een mailkoppeling gaat niet mee in een publicatie: elke organisatie koppelt haar eigen mailbox.
Wat het model leest als iets mislukt¶
Het model leest een vaste zin, nooit de woorden van de server, die een adres of een onderwerp kunnen noemen. De beurt gaat door.
| Het model leest | Wat er gebeurde |
|---|---|
Denied by policy. |
de host staat niet bij je toegestane hosts, de regels van de sleutel weigeren de tool, of de installatie blokkeert de host of het adres waar hij naar verwijst (een privé- of loopback-adres, een naam als localhost of een naam op .internal) |
This mailbox does not allow that folder. |
de map staat niet in folders |
Tool authentication failed. |
de server weigerde de login, of het token van de persoon is ingetrokken |
Mail server unreachable. |
de server antwoordde niet op tijd |
Mail server refused the request. |
de server weigerde de opdracht, bijvoorbeeld een uid die niet bestaat |
Message too large to read. |
het bericht is groter dan 25 MiB |
Mail server cannot search this text. |
de server kan niet zoeken op tekst buiten ASCII |
Mail tools are busy; try again shortly. |
Core heeft op dit moment geen plaats om de mailbox te openen |
This mailbox may not send to that domain. |
een ontvanger valt buiten send_allowed_domains |
Too many recipients for this mailbox. |
meer dan max_recipients ontvangers |
This mailbox has sent as many mails this hour as it may. |
de sends_per_hour van dit uur zijn op |
Bij een persoon zonder toestemming leest het model de zin met een inlog-URL uit Vraag de persoon
in te loggen, en bij een verzoek dat geen user noemt de zin This tool
needs a person's login, and the request named no user.
Bij het registreren of wijzigen:
| Status | Wanneer |
|---|---|
409 |
er is al een mailkoppeling met deze naam; of bij DELETE noemt een agent een van de tools nog |
422 |
een veld past niet, bijvoorbeeld watch.folder buiten folders, een poll_seconds onder de ondergrens, send_allowed_domains zonder smtp en from_address, mailbox bij de verkeerde soort auth, of een auth.client die je installatie niet kent |
503 |
de installatie heeft geen sleutel om het geheim mee te versleutelen, of, bij de mailbox van een persoon, geen publiek adres om na het inloggen naar terug te keren; vraag het je operator |
Elke route heeft een tweeling onder /tenants/{tenant_id}/mail_connectors voor een beheerder die
met een beheerderstoken werkt, met dezelfde velden en antwoorden.