Email automation
NCTS-T1 email triage: how a Venlo expediteur beat 16:30
It is 15:48 in Venlo. Six NCTS-T1 movement references sit unread, three from EORIs the desk has never seen, and the Aachen-Süd cut-off is forty minutes out.

The 16:30 problem
Picture the customs desk at a 29-person expediteur in Venlo on a Tuesday afternoon in February. It is 15:48. The shared mailbox holds 412 unread mails since the morning. Six of them are NCTS-T1 movement references for trailers that need to clear Aachen-Süd before the 16:30 Bundeszollverwaltung cut-off. Three carry sender EORIs the company has never seen before. The senior douane-expert is on a customer call. Junior staff are searching for the manifest in an Oracle 12c archive that returns nothing unless you spell the consignor name exactly the way it was typed in 2017.
If even one of those six T1s misses 16:30, the trailer sits at the border until morning, the driver burns out his hours under EU regulation 561/2006, and the customer phones before breakfast.
This was the situation we walked into in October 2025. Twelve weeks later the same desk processed an average of 2,940 customs mails per week without missing a single Aachen-Süd cut-off. This is how.
The legacy you cannot replace
Every freight forwarder we have worked with in the Netherlands, Germany, and Belgium has the same shape of tech stack: a customs filing platform bought before 2015, an in-house manifest archive that someone called Henk wrote in PL/SQL, an email client, and a wall calendar with the German federal holidays marked in red.
Our Venlo client ran Descartes Customs Filing for declarations and a homegrown Oracle 12c manifest archive that predated the current ownership. The Descartes installation worked. The Oracle archive worked. Both are out of formal vendor support — Oracle Database 12.2 dropped out of premier support in 2022 according to the Oracle Lifetime Support Policy — and neither was going anywhere in the next eighteen months. Try telling a 14-person operations team to swap their TMS in the middle of autumn peak.
So we migrated nothing. We put an email agent in front of the existing stack, gave it read credentials to both systems, and let the humans keep their tools.
What 2,940 weekly mails actually look like
The desk receives roughly five categories of mail per day:
- NCTS-T1 and T2 movement references from carriers asking for clearance — about 60% of volume.
- Manifest queries from receivers asking where their shipment is in the Oracle archive — about 18%.
- Bundeszollverwaltung correspondence: ATB notifications, control orders, release confirmations — about 12%.
- Internal handover mails between Venlo and the agent at Aachen-Süd — about 7%.
- Everything else: invoices, complaints, mailing lists, phishing — about 3%.
Before the project, every one of those mails landed in one shared mailbox: douane@. The desk sorted them by hand. The triage step alone burned about 14 hours per week, before anyone touched an actual declaration.
Why unknown EORIs are the whole game
An NCTS-T1 with a known sender EORI is a known problem. The desk has paperwork for that company, a credit check on file, and a pricing template. The mail can be auto-acknowledged and routed to the junior who handles that customer.
An NCTS-T1 with an unknown sender EORI is a different animal. It might be a new customer placing a first shipment. It might be a freight forwarder downstream that misdirected the mail. It might be fraud: someone trying to attach a clean importer profile to a dirty consignment. Until a human decides which, the safest thing is to stop.
The mistake teams make is to let those mails sit in the same queue as the routine ones. The senior expert finds them at 16:25, five minutes before cut-off, and is forced to choose: file the T1 against an unverified EORI and absorb the risk, or miss the deadline and lose the customer.
If you build a customs triage agent and it treats unknown-EORI T1s as just another classification problem, you have built a liability. The right design is to park them — visibly, loudly — in a separate queue with a deadline timer attached.
The agent, in three layers
The system has three layers. None of them are clever in isolation. The value comes from the connection.
Layer 1: classification with a customs-aware prompt
Every inbound mail is fetched over IMAP IDLE from the shared mailbox. A vision-capable model reads the body and any PDF attachments — most NCTS-T1 movement references arrive as PDF — and returns a JSON envelope:
{
"category": "ncts_t1",
"mrn": "26NL00000123456789",
"sender_eori": "NL854321987",
"consignor_name": "Vermeer Cargo BV",
"office_of_destination": "DE004600",
"estimated_arrival_utc": "2026-02-17T14:50:00Z",
"confidence": 0.94
}The category vocabulary is closed: nine values, mapped to the desk's existing folder structure. We did not invent a taxonomy. We copied the one the senior expert had been using for eleven years.
Layer 2: lookups against Descartes and Oracle
The EORI from layer 1 is checked against three sources in parallel:
- The Descartes Customs Filing customer table, exposed over its REST surface.
- The Oracle 12c manifest archive, via a read-only database user and a single indexed query on
consignor_eori. We added the index. It took eleven minutes of downtime on a Saturday. - The European Commission's public EORI validation service, to confirm the number is syntactically real and currently active.
If all three return a match and the EORI is on file with the customer, the mail moves to the routine queue, an acknowledgement is drafted, and the declaration is pre-filled in Descartes with the values from the JSON envelope. The human reviews and submits.
Layer 3: the douane-expert queue
If the EORI is not on file, or any one source returns nothing, the mail is parked in a separate Outlook folder named NCTS-onbekend. Every item in that folder has a sortable column showing the minutes remaining until the relevant German customs office cut-off. For Aachen-Süd that is 16:30 CET. For Kehl, 16:00. For Frankfurt-Flughafen, 17:30.
The senior expert opens that folder twice a day. Items are sorted by deadline ascending. The agent has already done the EORI lookup, attached the relevant manifest PDF from Oracle, and drafted three possible replies. The human reads, picks one, submits.
What the numbers say after twelve weeks
We track four metrics. The numbers below are the four-week rolling average for the period ending 13 June 2026.
- Mails handled per week: 2,940, up from 2,610. Volume grew because the desk took on a contract they had previously declined for capacity reasons.
- Triage time: 1.8 hours per week across the team, down from approximately 14.
- NCTS-T1s submitted after 16:00 for a 16:30 cut-off: 6 in twelve weeks, down from a baseline of roughly 40 per twelve weeks.
- Missed Aachen-Süd cut-offs: zero, down from three per quarter.
The number that the customer cares about most is the last one. Zero missed cut-offs over a full peak quarter is what justifies the project. Everything else is gravy.
The gotchas we hit
Three things did not go to plan, and they are worth naming.
Descartes API rate limits. The REST surface on the on-premise Descartes installation will happily 429 you if you fan out more than six concurrent customer lookups. We ended up with a small Redis-backed semaphore in front of every Descartes call. Boring. Necessary.
Oracle 12c character sets. The legacy archive was created with WE8MSWIN1252 as the database character set. Consignor names with Polish or Czech diacritics — Łukasiewicz, Šafařík — were stored as mojibake. Our exact-match query missed them. We rebuilt the index against a normalised lowercase ASCII column and recall went from 71% to 99.4%.
The 16:30 timer is not 16:30. The Bundeszollverwaltung publishes 16:30 as the cut-off for Aachen-Süd, but in practice the office stops accepting new T1s at 16:15 on Fridays before a federal holiday. The senior expert knew this. The agent did not, until we added a German holiday calendar and a Friday-eve rule.
A customs email agent, stripped to its skeleton, is a routing system with a deadline clock attached. The model decides what kind of mail it is. The lookups decide whether a human needs to see it. The clock decides who panics.
What we would do differently
The biggest mistake we made was scoping the first sprint around "classify and reply." We should have scoped it around "park the unknowns." Classification on its own buys you about three hours per week. Parking unknowns into a deadline-sorted queue is what buys you the missed-cut-off number, and that is the number a freight forwarder will write a renewal cheque for.
If you are looking at a similar problem, here is the smallest version of the build that would have proven the case in week one: a script that reads the shared mailbox, runs every inbound NCTS-T1 PDF through a vision model, extracts the sender EORI, queries your customer table, and dumps every miss into a folder called NCTS-onbekend with a column showing minutes-to-cut-off. That alone, before any reply drafting or any database integration, would have saved this desk three afternoons in the first month.
When we built the email agent for the Venlo desk, the thing we kept running into was the Oracle character-set issue above. We ended up solving it with a normalised ASCII index and a nightly reconciliation job, but the lesson stuck: the legacy database is always weirder than the README claims.
If you run a customs or logistics desk today, the five-minute audit is this: open your shared mailbox, sort by sender, and count how many mails this week came from EORIs that are not in your customer table. That number is the size of your triage problem.
Key takeaway
Customs email automation is a routing system with a deadline clock attached: park every unknown-EORI T1 in its own queue, sorted by minutes to cut-off.
FAQ
Why not migrate off Descartes Customs Filing and Oracle 12c first?
Both systems work and the team knows them. Replacing a TMS during autumn peak is a guaranteed disaster. The agent sits in front of the existing stack with read credentials, no migration needed.
What happens to an NCTS-T1 with an unknown sender EORI?
It is parked in a separate Outlook folder called NCTS-onbekend with a column showing minutes remaining until the destination office's cut-off. The senior expert handles that folder twice a day.
How does the agent know when the Aachen-Süd cut-off shifts?
We added a German federal holiday calendar and a rule that pulls the cut-off forward to 16:15 on the Friday before any public holiday. The published 16:30 figure is not always the real one.
What was the single biggest win in the project?
Zero missed Aachen-Süd cut-offs across a full peak quarter, down from three per quarter. That is the metric that justified the build and the renewal.