← Blog

Email automation

E-mailagent voor cargo claims: van 2u10 naar 14 minuten

Dinsdagochtend bij een koffie-importeur in Maastricht. De operations lead opent haar inbox: 124 marine cargo claim-threads. Vorig jaar deed ze er 2u10 over. Dit jaar 14 minuten.

Jacob Molkenboer· Oprichter · A Brand New Company· 11 jun 2026· 10 min
Crème envelop met limoengroen lint op ivoorlinnen vloei, messing paperclip en verzendlabel met touw ernaast.

De operations lead bij een Maastrichtse specialty-coffee importeur opent haar laptop om 06:48. Sanco container SANU4521789 heeft gisteren afgemeerd in Rotterdam. 320 zakken Kenya AA uit Embu hadden droog moeten zijn. Twee zijn dat niet. De expert staat over 90 minuten op de ontvangstvloer. Ondertussen heeft haar inbox 137 ongelezen threads, de meeste over andere containers, andere claims, andere notifications of loss die wachten op hun klok van drie dagen onder Hague-Visby.

Een jaar geleden was ze tot de koffiepauze bezig geweest met sorteren. Vanochtend doet ze er veertien minuten over. De reden is een e-mailagent die we in maart voor haar team hebben gebouwd. Dit is wat hij doet, en wat hem bijna brak.

De vorm van het probleem

De importeur (33 mensen, ongeveer €18M omzet, vier herkomstlanden, twee warehouses) had een stabiele operationele nachtmerrie. Marine cargo komt binnen via containers uit Mombasa, Santos, Guayaquil en Sumatra. Ongeveer één op de 14 containers triggert een vorm van cargo claim: waterinslag door een gescheurde deurseal, condensschade door een reefer die in de zon stond in Algeciras, diefstal in Beiroet, manco bij devanning. De claims-correspondentie loopt via Lloyd's-syndicate cargo underwriters en een handvol agenten.

Het volume is niet rampzalig. 620 claim-gerelateerde e-mailthreads landen elke week in de gedeelde inbox. De ramp zit in de timing. Onder de Hague-Visby Rules, Artikel III(6) heeft de geadresseerde drie dagen vanaf aflevering om schriftelijk kennis te geven van verlies of schade die niet zichtbaar is bij outturn. Mis het venster en de vervoerder wordt geacht de cargo te hebben afgeleverd in de staat zoals beschreven in het cognossement. De verhaalsactie van de verzekeraar tegen de vervoerder sterft daar. De claim wordt nog steeds uitbetaald, maar de schade-expert noteert de gemiste notice, en bij de volgende verlenging eet de importeur dat op in premie.

De ochtendroutine van de operations lead was dus een triage-oefening met juridische tanden geworden. Vind de threads die een container noemen die in de afgelopen 72 uur is gelost. Vind degene die schade, manco of notify noemen. Cross-reference elke container-ID tegen de Sanco container-feed om de daadwerkelijke POD-timestamp te bevestigen, want subject lines liegen. Stuur de notify-of-loss brief, of jaag de agent op die er een had moeten sturen. Daarna alles wat overblijft.

Twee uur en tien minuten op een normale dinsdag. Drie uur op een maandag na een rustig weekend aan de carrier desk. Tegen de tijd dat ze bij de rest van de inbox kwam, riep de loods al op haar portofoon.

Wat de agent doet, in normaal Nederlands

We hebben een e-mailagent op de gedeelde claims@-mailbox gezet. Hij leest nieuwe berichten via IMAP IDLE, classificeert ze, verrijkt ze met containerdata en stelt óf een antwoord op óf verplaatst de thread naar een van vier gelabelde buckets. De operations lead opent haar inbox met die buckets al gesorteerd. Ze werkt eerst de urgente weg, dan de tweede, en de rest tegen de tijd dat haar koffie koud is.

De vier buckets:

  • NOL-klok loopt. Een claim die binnen 72 uur een notify-of-loss brief nodig heeft. Gesorteerd op uren resterend.
  • Wachten op vervoerder of expert. Wij hebben iets gestuurd. De andere kant moet reageren. Wij rappelleren op dag 5, dag 10, dag 14.
  • Wachten op ons. De vervoerder of verzekeraar heeft een vraag terug. Gesorteerd op claimomvang.
  • Alleen ter referentie. Geen actie deze week. Gearchiveerd, geïndexeerd, doorzoekbaar.

Classificatie gebeurt met een klein model, fine-tuned op drie maanden handmatig sorteerwerk van de operations lead. We keken toe terwijl ze threads naar folders sleepte over IMAP, behandelden die verplaatsingen als labels en trainden op het resultaat. Na zes weken zat haar overeenstemming met het model op 97%. De resterende 3% waren threads waar twee competente mensen het ook oneens over zouden zijn welke bucket de juiste was.

Dat klinkt simpel. Het interessante werk gebeurt in de enrichment-stap.

De Sanco-feed en het subject-line probleem

Elke claim-relevante thread noemt minstens één container-ID. Ze zijn regex-vriendelijk: vier letters dan zeven cijfers, met een check digit die je kunt valideren tegen het ISO 6346-algoritme. Makkelijk te extraheren.

De valkuil is dat het onderwerp leest als Re: SANU4521789 - notice of loss, terwijl de body drie containers kan opsommen, waarvan er maar één deze week daadwerkelijk in Rotterdam is gelost. De andere twee zijn elf dagen geleden klaar met lossen in Antwerpen, ruim na het notice-venster, en ze worden als context geciteerd, niet als onderwerp van de claim.

Dus we vertrouwen het onderwerp niet. We trekken elke container-ID uit de body, valideren elk en zoeken elk op tegen de Sanco container-milestone-feed. De feed is een gepolde JSON-endpoint, elke vijftien minuten gepusht naar een kleine staging-tabel. Voor elke container zijn de relevante velden de daadwerkelijke gate-out datum, de proof-of-delivery datum, en de losplaats. De notify-of-loss klok start bij proof of delivery, niet bij gate-out. Dat hebben we op de dure manier geleerd.

Hier is de deadline-calculator, vereenvoudigd voor leesbaarheid:

type ContainerEvent = {
  containerId: string
  dischargePort: string
  podAt: string | null     // ISO timestamp, may be null
  gateOutAt: string | null
}

function nolDeadline(event: ContainerEvent, now: Date): {
  deadline: Date | null
  hoursRemaining: number | null
  basis: 'pod' | 'gate-out-fallback' | 'unknown'
} {
  // Hague-Visby Article III(6): three days from delivery for
  // non-apparent damage. We treat POD as delivery.
  if (event.podAt) {
    const pod = new Date(event.podAt)
    const deadline = new Date(pod.getTime() + 3 * 24 * 3600 * 1000)
    return {
      deadline,
      hoursRemaining: (deadline.getTime() - now.getTime()) / 3600_000,
      basis: 'pod',
    }
  }
  // No POD yet. Fall back to gate-out plus a buffer for
  // transport to the consignee warehouse. Flag for review.
  if (event.gateOutAt) {
    const gate = new Date(event.gateOutAt)
    const deadline = new Date(gate.getTime() + 5 * 24 * 3600 * 1000)
    return {
      deadline,
      hoursRemaining: (deadline.getTime() - now.getTime()) / 3600_000,
      basis: 'gate-out-fallback',
    }
  }
  return { deadline: null, hoursRemaining: null, basis: 'unknown' }
}

Het fallback-pad doet ertoe. Ongeveer 4% van de claims komt binnen voordat de Sanco-feed de POD heeft ingehaald. We willen niet dat de agent die threads stil afwaardeert. Het veld basis komt terug in het inbox-label, zodat de operations lead in één oogopslag ziet welke deadlines hard zijn en welke schattingen.

Wat brak

In de eerste zes weken braken drie dingen. Elk leerde ons iets.

De bonded-warehouse pass-through

Twee containers per maand passeren een bonded warehouse in Antwerpen voor ze doorgaan naar Maastricht. De Sanco-feed beschouwt de afgifte in Antwerpen als POD. De daadwerkelijke ontvangstvloer staat in Limburg, drie dagen later. We waren notify-of-loss klokken aan het sluiten die nog niet eens waren begonnen. De fix: een kleine lookup-tabel van bonded handlers per herkomstroute, met een override per container.

De reply-all reactie-storm

De auto-responder van een schade-expert raakte in een loop met de auto-responder van een surveybureau. De agent zag 38 berichten uit dezelfde thread in twee minuten en stelde plichtsgetrouw 38 antwoorden op. We hadden een queue, maar geen debounce per thread. Die hebben we toegevoegd: maximaal één uitgaande draft per thread per zes uur, met een handmatige override die de operations lead kan aanklikken. Er zijn geen productie-antwoorden de deur uit gegaan. De drafts zaten in haar outbox te wachten op haar hand.

Dat was de eerste les, en degene die vooraf het meest voor de hand had moeten liggen. Elke e-mailagent die antwoorden opstelt, moet alleen opstellen. Productieverzending is een aparte, bewuste gebruikersactie. We zijn niet teruggekomen op die beslissing, en de recente reeks koppen over agents die ongesuperviseerd in productiesystemen rommelen, heeft daar niets aan veranderd.

De container-ID die er geen was

Een langlopende claim-thread verwees naar een projectcode die toevallig precies in het ISO 6346-formaat paste: vier letters, zeven cijfers, geldige check digit. De agent bleef die proberen te verrijken via de containerfeed en kreeg telkens een leeg antwoord. Hij viel correct terug op de unknown-basis, maar de lege enrichment triggerde een dagelijkse Slack-alert. We hebben een confidence score toegevoegd: een container-ID telt pas als de carrier-prefix overeenkomt met een bekende vervoerder die geregistreerd staat bij de traffic department van de importeur.

Wat de cijfers zeggen

Zes weken na de uitrol hebben we gemeten. De methodologie was simpel: ze startte een timer bij het openen van de inbox en stopte hem als ze alles getriaged had wat niet was geparkeerd als reference-only. We hebben twaalf werkdagen gemiddeld.

  • Gemiddelde ochtendtriage: 14 minuten, omlaag van 2u10.
  • Gemiste notify-of-loss deadlines in de meetperiode: 0, tegen een baseline van drie in het kwartaal ervoor.
  • Verwerkt claim-threadvolume: 620 per week, waarvan de agent 71% volledig afhandelde zonder menselijke input. De rest raakte zij aan.
  • Totaal aantal agent-drafts dat na haar review naar productie ging: rond de 180 per week. Eén op de vijf herschrijft ze.

Eén getal dat we niet formeel bijhielden maar wel in de gaten hielden. De classification confidence op Portugese threads lag de eerste maand ongeveer acht punten lager dan op Engelse, en drie punten lager tegen week zes. We hebben het model niet hertraind. De verbetering kwam uit de correcties van de operations lead die als drift-correctievoorbeelden terugvloeiden in de labeled set, en uit haar gewoonte om elke thread die de agent zichtbaar verkeerd las door te sturen naar een kleine drift@-alias die we precies daarvoor hadden ingericht.

Het eurobedrag is lastiger vast te pinnen, omdat de verhaalswaarde van een enkele claim schommelt tussen €600 en €40.000. De schade-expert van de verzekeraar vertelde ons, off the record, dat het missed-notice percentage bij deze importeur was gegaan van merkbaar naar best in zijn portefeuille. Dat ga je terugzien bij de verlenging.

Takeaway

Een e-mailagent verdient zichzelf terug wanneer de prijs van een gemiste deadline hoog is en het inboxvolume stabiel. De meeste inboxen voldoen daar niet aan. Marine cargo claims wel.

Wat we niet meer zo zouden doen

Drie architectuurkeuzes uit week één zouden we opnieuw bekijken.

Ten eerste hebben we de staging-tabel van de Sanco-feed in dezelfde Postgres gehost als de eigen state van de agent. Daarmee koppel je twee dingen die met verschillende snelheden veranderen. Het feed-schema is eigendom van de vervoerder, die op een dinsdag een kolom hernoemt. De state van de agent is van ons. Volgende keer houden we ze minstens in aparte schema's, en waarschijnlijk in aparte databases.

Ten tweede schreven we onze eigen retry-logica voor de IMAP IDLE-connectie. Die code is nu 280 regels en heeft vier bugs gehad. Er bestaan goede libraries voor. We hoefden hem niet zelf te schrijven. Hetzelfde geldt voor de orchestration loop: open-source projecten zoals Burr modelleren agent-state-machines al netjes, en je eigen variant bouwen kost je debug-tijd die je niet had ingepland.

Ten derde bouwden we een language classifier om prompts naar taalspecifieke templates te routeren. In de praktijk is een marine cargo claim half Engels boilerplate met daaromheen twee alinea's in welke taal de herkomstagent ook schrijft, vaak met een verdwaalde zin in een derde taal van een co-loader. We voeren nu elke body aan één meertalige prompt en laten die het zelf uitzoeken. De classifier loste een probleem op dat in productie niet bestond.

Het kleinste wat je vandaag kunt doen

Als je een operations-inbox beheert die deadline-gevoelige correspondentie verwerkt, open hem nu en tel twee getallen. Hoeveel threads zijn er in de laatste 24 uur geland? Hoeveel daarvan verwijzen naar een externe identifier (een container, een factuurnummer, een dossiernummer) die je in code zou kunnen oplossen tegen een gezaghebbend systeem? Als beide getallen niet-triviaal zijn, heb je een probleem in de vorm van een agent.

Toen we de claims-agent voor de Maastrichtse importeur bouwden, was het ding waar we tegenaan liepen niet de model-accuratesse. Het was het saaie spul: container-ID disambiguatie, POD versus gate-out semantiek, debounce op auto-responders. De taallaag verwerkte Engels, Nederlands, Portugees en Spaans zonder erover te struikelen. Wil je weten of jouw inbox dezelfde vorm heeft, dan begint ons werk aan AI-agents meestal met een audit van een uur op je laatste 200 threads. Dat is het gesprek, geen sales pitch.

Kern

Een e-mailagent loont wanneer de prijs van een gemiste deadline hoog is en het inboxvolume stabiel. De meeste inboxen voldoen daar niet aan. Marine cargo claims wel.

FAQ

Hoe gaat de agent om met niet-Engelse claim-correspondentie?

Hij leest Engels, Nederlands, Portugees en Spaans out of the box. Container-ID's en datums zijn taalonafhankelijk. Vrije body-tekst gaat naar één meertalige prompt in plaats van een gerouteerde per taal. In de praktijk werkt dat beter dan taaldetectie.

Wat gebeurt er als de Sanco-feed vertraagd of plat is?

De deadline-calculator valt terug op de gate-out datum plus vijf dagen en flagt de thread voor menselijke review. De operations lead ziet een expliciet schattingslabel, geen harde deadline.

Verstuurt de agent zelf antwoorden?

Nee. Hij stelt drafts op. De operations lead klikt op verzenden. Een ontspoorde auto-responder-loop in week drie heeft ons ervan overtuigd dat de draft-only grens de veilige is, en daar zijn we bij gebleven.

Hoe lang duurde de uitrol?

Twee weken bouwen, vier weken gesuperviseerd parallel draaien. We hebben de handmatige workflow pas uitgezet toen het aantal gemiste deadlines drie weken op rij nul was.

email automationai agentscase studyworkflowoperationsintegrations

Iets bouwen?

Start een project