Ga naar inhoud

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.

  1. Registreer de koppeling met de gegevens van je provider. Vraag naast de scope voor IMAP ook openid en email: 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>"]}}'
    
  2. Registreer <de publieke basis-URL van Core>/api/v1/oauth/callback als redirect-URI bij je provider.

  3. Noem de persoon met user op 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 url uit het antwoord aan de persoon. GET .../authorizations/{user} zegt of Core haar toestemming heeft, en DELETE .../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.