← Blog

Email automation

Email agent for a schadeherstel chain: the BR7 playbook

An Apeldoorn schadeherstel-keten sends 2,260 emails to verzekeraars a week. The agent we shipped drafts most of them — and refuses, on principle, to touch anything above €7,500.

Jacob Molkenboer· Founder · A Brand New Company· 19 Jun 2026· 9 min
Cream envelope tied with chartreuse ribbon on dark green leather blotter, brass bell and carbon-copy slip beside it.

It is 07:42 on a Tuesday in Apeldoorn. The planner opens her inbox at the schadeherstel-keten and counts 184 new ABZ-berichten from overnight. By 18:00 another 412 will land. Most are routine: foto-aanvragen, akkoord-mails, calculatie-bevestigingen. A handful are not, and those are the ones she would rather catch before the agent does.

The chain runs five vestigingen, thirty people, and roughly 2,260 inbound verzekeraar-correspondenties a week. They asked us to build an email agent that would draft replies. We agreed, with one condition: the agent would not be allowed to touch a single casco-claim above €7,500. This is the playbook for the version we shipped, the rules we did not let it cross, and the one week we almost shipped it wrong.

The shape of 2,260 messages a week

Before any of the AI work, we sat in the planning room for two mornings with a printout. Twelve verzekeraars. Eight inbound message types, dominated by three: FOTO_VERZOEK, AKKOORD_VERZOEK, and CALCULATIE_OK. Eighty-one percent of the traffic followed one of four scripted reply patterns. Eleven percent needed a planner to look at a photo and decide. The remaining eight percent were the messages that, if you handled them wrong, ended in a phone call from the expertise-bureau two weeks later.

Three planners were spending roughly ninety minutes each morning sorting messages by hand before the first car was lifted onto the bridge. That was the spreadsheet that told us this was worth doing. Not "AI for the inbox" — "the three of you get ninety minutes back each morning, and the dossiers stop slipping a day behind on Mondays." That is the only sentence in the kickoff deck that mattered.

The stack we inherited

Two systems, neither of which wanted to talk to the other. The first was the ABZ Nederland EDI-broker, speaking EDIFACT through the SCHA-berichten the Dutch insurance industry has been on since the mid-2000s. Boring, well-documented, completely fine. The chain has been on it since 2012 — 14 years of habits baked into the planners' fingers and into every export template the office staff trust.

The second system was the schadedossier-systeem built by ICT Automatisering in 2014. Windows Server. SQL Server backend. No public API. The consultant who built it had encrypted the database password in a config file and then, somewhere between 2017 and the day he retired, misplaced the key. The current IT lead had a working read-only DBA account and the polite request to please not break anything before the planned 2027 vervanging.

So we wrote a sidecar. A small Go service that pulled XML exports out of the ABZ-broker, joined them against the read-only SQL view we were allowed to touch, and wrote the result to a Postgres mirror the agent would actually reason over. The legacy systems stayed exactly as they were. Nothing got migrated. Nothing got rewritten. We only had to be right about what we read.

Why €7,500 is the line

Bedrijfsregeling 7 is the Dutch insurance industry's self-regulation on motor damage claims, published by the Verbond van Verzekeraars. Under BR7, two insurers handling a collision between their respective klanten do not invoice each other below a per-claim threshold; they net it out through a clearing. The threshold for casco sits at €7,500.

Above that line, the dossier becomes formal. An expert is involved, the calculatie is independently checked, and the akkoord-mail you send is not a courtesy — it is a binding step in a process that may end at arbitrage. The cost of a wrong email above the line is measured in months of dispute and weeks of management time.

That is why the agent does not get to touch claims above €7,500. Not because the model could not draft a competent email above the line; it absolutely could. Because the cost of a competent-looking but subtly wrong email above the line is qualitatively different from the cost below it. The €7,500 line is not arbitrary. It is the line BR7 itself draws between the two regimes, and we chose to draw the agent's line directly on top of it.

Warning

If a regulation already draws a line, draw the agent's line on top of it. Do not negotiate a new one. A planner can always escalate a €4,000 claim into the expert-queue; a planner cannot un-send a binding email.

The queue split, in three rules

Every inbound ABZ-bericht hits a router before the agent sees it. The rules are short and the order matters. Threshold first, expert-flag second, tegenpartij-afwijkend third. Anything that falls through lands in the agent's draft-lane.

// claim-router.ts — runs on every inbound ABZ SCHA-bericht
type Lane = 'expert-queue' | 'agent-draft'

export async function route(msg: SchaMessage): Promise<{ lane: Lane; reason: string | null }> {
  const claim = await loadClaim(msg.dossierId)
  const casco = claim.coverage === 'CASCO'
  // Read BOTH calculaties, take the higher. See the gotcha below.
  const ourCents   = claim.calculatie?.totaal_excl_btw_cents ?? 0
  const theirCents = claim.tegenpartijCalculatie?.totaal_excl_btw_cents ?? 0
  const amountCents = Math.max(ourCents, theirCents)

  // Rule 1: BR7 threshold. Cents, not euros, so we never round.
  if (casco && amountCents >= 750_000) {
    return { lane: 'expert-queue', reason: 'BR7-threshold' }
  }

  // Rule 2: A planner has already flagged the dossier for expertise.
  if (claim.expertVlag) {
    return { lane: 'expert-queue', reason: 'expert-flag-set' }
  }

  // Rule 3: Counterparty disputes the toedracht.
  if (claim.tegenpartij?.afwijkend === true) {
    return { lane: 'expert-queue', reason: 'tegenpartij-afwijkend' }
  }

  return { lane: 'agent-draft', reason: null }
}

Cents, not euros. We learned that in week three, when a Postgres numeric(10,2) rounded a €7,499.995 calculatie into a €7,500.00 routing decision that a planner spent forty minutes unwinding. Money lives in integer cents. Always.

What the agent actually drafts

Inside the agent-draft lane the work is narrow, on purpose. The agent only writes four kinds of email. A reply to a FOTO_VERZOEK that confirms the foto-set is uploaded, references the seven specific photo-hoeken the verzekeraar's portal expects, and links to the dossier. An AKKOORD reply that acknowledges the calculatie, names the Audatex-referentie, and confirms the planned reparatiestart-datum. A CALCULATIE_OK follow-up that thanks the schade-behandelaar by name and confirms the factuur-route. And a short fallback email that says "we hebben uw bericht ontvangen, een planner reageert vandaag voor 16:00" — sent only when the other three templates do not fit cleanly.

Four templates. That is the entire surface area. Not a free-form composer dressed in a system prompt. Four templates with named placeholders that the dossier either fills or does not.

The shape of the prompt

The system prompt is short and brutal. We give the model the dossier as JSON, the inbound ABZ-bericht as plain text, the four templates with their exact placeholders, and one sentence: "produce exactly one of the four templates with placeholders filled, or output the token DECLINE." There is no chain-of-thought in the output, no explanation, no apology. The agent either gives us a filled template or it gives us DECLINE, and DECLINE routes to a planner with a one-line note.

Temperature is 0.1. The model has no tools, no memory across calls, and no way to read anything outside the JSON payload we handed it. A second pass — a deterministic linter — checks that the output matches one of the four template shapes byte-for-byte in structure and that every required placeholder has a value drawn from the dossier. If the linter rejects, the planner gets the inbound message and a "linter failed" note instead of a draft. Two layers, both cheap, both right almost all of the time. In the first month, the model declined on 4.1% of messages and the linter caught another 0.6%. The planners told us to stop apologising for that number — they prefer a handed-off message to a confidently wrong one.

The audit trail BR7 demands

BR7 is not just a threshold. It is also a paper trail. For every claim, you have to be able to reconstruct, two years later, who said what and when. The planners had been doing this by saving emails into a per-dossier folder on the file server. We did not change that habit.

Every email the agent drafts is written to the same per-dossier folder before it is sent, with a sidecar JSON file that records: the inbound ABZ-bericht ID, the model version, the prompt snapshot hash, the four-template choice, the placeholders the model filled, the planner who approved it, and the timestamp. Two years from now, if an expertise-bureau asks why a particular akkoord went out on a Wednesday in June 2026, the answer is one folder away.

That sidecar is the difference between an AI tool and an AI tool a regulated business will actually run. The audit is not a feature. It is the product.

The week we almost shipped it wrong

Two weeks before go-live we ran a parallel mode: the agent drafted, the planners reviewed, nothing went out without a click. On day three of the parallel run, the agent confidently drafted an akkoord-mail on a claim that, on paper, sat at €6,940 — under the line. The planner who reviewed it noticed the dossier had a second calculatie attached, from the tegenpartij's expert, for €11,200.

The first calculatie was ours. The second was the counterparty's. Our router had read only the first. Below €7,500 on our number, above €7,500 in the dossier's reality. We changed Rule 1 that afternoon to read both calculaties and route on the maximum. The agent never drafted that email in production. The parallel run is the reason.

If you are shipping anything that drafts on behalf of a regulated party, run it in parallel for at least two weeks, and explicitly look for the cases where the agent looks right and is not. Those are the only cases that matter. Volume is easy to measure. Quietly-wrong is the metric you have to invent.

What stayed with the planners

After three months in production the agent handles 71% of inbound ABZ-traffic end-to-end. The planners spend roughly twenty minutes — not ninety — sorting in the morning. The expert-queue has averaged 38 claims a week, every one of them looked at by a human. The chain has not had a BR7-related dispute since go-live. We will revisit that claim in six months.

When we built the email-agent for this Apeldoorn schadeherstel-keten, the thing we kept running into was that the legacy schadedossier-systeem could not be touched, and the regulation could not be negotiated. We solved it by writing a small read-only mirror, drawing the agent's line exactly where BR7 already drew its own, and refusing to let the model anywhere near the dossiers it would have looked competent on.

If you have an inbox shaped like this one, the smallest useful thing you can do today is print one morning's messages, sort them by type, and circle the four templates that would cover eighty percent. That circle is the agent. Everything else stays with the planners.

Key takeaway

If a regulation already draws a line, draw the agent's line on top of it — never one euro lower, never one cent higher, and never negotiable.

FAQ

Why €7,500 specifically?

It is the casco-threshold under Bedrijfsregeling 7. Below the line, insurers net through a clearing; above it, the dossier is formal and the akkoord-mail is a binding step that can end at arbitrage.

Could you not just give the model the BR7 rules and let it decide above the line?

You could, but you would be asking a probabilistic system to be right under regulatory pressure on the cases that hurt most. A deterministic router below the line and a human queue above it is cheaper and safer.

Why mirror the legacy database instead of integrating directly?

The ICT Automatisering schadedossier-systeem had no public API and a misplaced password key on its encrypted config. A read-only Postgres mirror let us build without touching the original or waiting for the 2027 replacement.

How long did the parallel run last before go-live?

Two weeks, with every drafted email reviewed by a planner before sending. The parallel run caught the second-calculatie edge case that would otherwise have shipped on day three.

What happens when the model declines or the linter rejects?

The inbound message is routed straight to a planner with a one-line note. About 4.7% of messages land in that lane in a normal week. Planners told us to stop apologising for the number.

email automationai agentsautomationcase studyworkflowintegrations

Building something?

Start a project