Email triage with Smart Agents: from inbox to journal entry
The SA Email Handler codeunit is 1,141 lines of the email platform polling, intent extraction, and BC posting. Here is what happens between an email arriving and a draft journal landing in the user's outbox.
By Smart Agents Team
Most BC back-office work arrives as email. "Please send me the September statement." "Can you confirm we received the shipment yesterday?" "What was the price on PO 1042 line 2?" Every one of those is a request the AR clerk, the warehouse lead, or the buyer eventually answers by hand, by opening BC, doing the lookup, copying numbers into a reply, and clicking Send. Multiplied by a few dozen mailboxes and a few hundred messages a week, it is a real chunk of the working day.
Smart Agents has an email channel because that work is too repetitive to keep doing by hand and too sensitive to hand to a generic chatbot. The implementation lives in SA Email Handler QUA. At 1,141 lines of AL it is the biggest codeunit in the extension by some margin, and the size is honest: handling email well in 2026 means dealing with the email platform authentication, message threading, attachment normalization, intent classification, and a dozen edge cases nobody warns you about until you ship the feature.
THE PIPELINE
The pipeline is straightforward to describe and unpleasant to implement. A scheduled task (SA Email JQ Runner) wakes up on a configurable interval (the SA Email Handler exposes MaxPollSeconds and PollIntervalMs as configurable values, defaulted in the Smart Agent Setup). The handler iterates active agents that have the Email Enabled flag set on the Smart Agent table and a non-empty Email Address.
For each agent, it acquires a the email platform access token using the secure authentication client-credentials flow, with the client secret stored in Azure Key Vault for production tenants. It calls Graph at https://graph.microsoft.com/v1.0 to list unread messages in the agent's mailbox since the agent's Last Email Check timestamp. Then it iterates the messages.
For each message the handler does five things in order. It logs the message to SA Email Log with sender, subject, received-at, and a status of Received. It extracts the message body, normalizes attachments, and resolves the sender against the BC Contact and Customer tables (so an email from a known customer's primary contact is tagged with the customer number). It hands the body and the resolved context to the Smart Agent Chat Engine as a synthetic user message scoped to the agent. It waits for the chat engine to return with a draft reply and a structured set of tool calls. It posts the draft reply back to Graph as a draft email in the mailbox owner's Drafts folder, ready for review.
If the chat engine returns a write-action that the agent's autonomy level requires confirmation for (a journal post, a report run, a record edit), the agent does not execute it. The draft email contains the proposal, and the user opens BC to confirm.
INTENT EXTRACTION
The intent extraction is the part most teams underestimate. Customers do not write polite, structured tickets; they write "hey send me septembers statement and also can you check the shipping address i think we moved." The agent has to understand that this is two requests, that the customer ID needs to be resolved from the email address, that the September statement should use the agent's existing statement-generation tool, and that the shipping address change is not something the agent should silently make: it should flag for the user.
The Smart Agent Chat Engine handles the multi-intent case by returning a structured action plan: the agent says "I will draft the statement; I will note the address-change request in the reply for the user to verify with the customer." The user reviews the draft email, sees both items, and decides what to do with the address request. No silent writes to the customer record.
A WORKED EXAMPLE
A customer emails invoicing@yourcompany.com from her usual address with the subject "September statement please." Within one polling interval (default 60 seconds, configurable down to 30 in the setup):
The SA Email Handler picks up the message, logs it, resolves the sender to customer 10000.
It builds a synthetic chat message: "Customer 10000 has requested a September statement. Generate it and draft a reply." It hands the message to the chat engine.
The chat engine, running the agent on the Smart tier, calls the format-statement tool. The tool reads Customer 10000 and pulls the September entries from the Customer Ledger Entry table. It produces a PDF.
The chat engine drafts the reply email body ("Dear Maria, please find attached your September statement") and asks the email handler to attach the PDF.
The email handler creates a draft in invoicing@yourcompany.com's Drafts folder with the PDF attached, the body, the customer address, and a subject of "Re: September statement please."
The SA Tool Call Log table records every step: which tool was called, by which agent, on behalf of which user (the mailbox owner), against which customer, with what token counts and credit cost.
The AR clerk opens her Drafts folder a few minutes later, reads the draft, and clicks Send. Total credit cost on the Smart tier for this workflow: about 0.6 credits, or roughly six tenths of a euro cent (the math is in the related blog post on credits).
Multiplied by a hundred statement requests at month-end, the AR team sends a hundred statements in the time it used to take to send fifteen. The audit log proves it.
WHAT THE EMAIL CHANNEL DOES NOT DO
The email channel does not auto-send by default. Every reply lands in Drafts. You can promote a specific template to execute autonomy so it sends without review, but we do not recommend that for external customer mail at all, and we do not recommend it for internal mail until you have watched a couple of hundred drafts look right. The risk of an unreviewed email containing the wrong number, the wrong customer, or the wrong tone is higher than the small benefit of skipping the review click.
The email channel also does not currently parse attachments deeply (PDF OCR for an attached invoice request is on the roadmap; today the agent reads the body and any plain-text attachment).
FAILURE MODES
Graph API errors are returned as ERR-prefixed strings from the email polling procedure and surfaced in the SA Email Log row for that polling cycle, with a non-OK status. Common causes: an expired or revoked Graph token, a mailbox the OAuth app no longer has delegated permission for, or a transient the email platform throttling response. The handler retries with automatic retries and surfaces persistent failures via the Smart Agent Notification table so the admin sees them on the next BC sign-in.
If the chat engine returns an error (the model timed out, the credit balance was insufficient, the tool call failed), the email is left as unread in Graph and re-attempted on the next polling cycle. There is no silent loss.
GOVERNANCE NOTES
The email channel inherits all four governance layers from the rest of the agent stack (see the related blog post on tool autonomy). The mailbox the agent reads is the one your IT team explicitly delegated; the agent cannot read other mailboxes. The data the agent touches in BC is whatever the mailbox owner's BC user can see; the agent does not have its own permissions. Every email and every tool call is logged. Compliance teams that have accepted the email platform for other automations have already accepted the underlying surface; what they get on top is a row-level audit per email.
For setup, see /docs/admin for the email channel walkthrough and the FAQ entry on configuring the email platform permissions for the agent mailbox.