Audit-log every email your AI agent sends Nylas engineer details an architecture for audit-logging every email an AI agent sends, emphasizing that the live mailbox is not an audit trail. The design uses a separate immutable store, capturing outbound message IDs and inbound webhooks to create a defensible record. The post provides CLI commands for provisioning an Agent Account and outlines the pattern for building a write-once-read-many audit log. When an autonomous agent gets an email address of its own, the first question your security team asks isn't "can it send mail?" It's "can you prove, six months from now, exactly what it said and to whom?" That's a different problem from "does it work." A demo that fires off a few support replies looks great in a sprint review. But the moment a real customer says "your bot promised me a refund," or a regulator asks for the complete record of what an automated system told a data subject, you need a defensible trail — an immutable record of every outbound and inbound message the agent touched, captured outside the mailbox the agent can also delete from. I work on the Nylas CLI, so the terminal commands below are the exact ones I reach for. But the architectural point here is provider-agnostic and it's the part most "AI email" tutorials skip: the live mailbox is not your audit log. It's mutable, it has retention limits, and the same agent that sends mail can also trash it. If your only record of what the agent did lives in the inbox, you don't have an audit trail — you have a working copy. There are two stores in this design, and keeping them separate is the whole point. message id and thread id . Nothing in it is ever updated or deleted in normal operation. This is the record you hand a reviewer.The audit store is the thing you build. Nylas gives you the two capture points — the send response and the inbound webhook — but the immutability is your responsibility. That means a WORM write-once-read-many object store, an append-only table with no UPDATE / DELETE grant for the app role, or a hash-chained log where each entry commits to the hash of the previous one so tampering is detectable. Pick whichever your compliance posture demands; the capture pattern below is the same regardless. One thing I want to be honest about up front: custom metadata is not supported on Agent Accounts. On a normal connected grant you might be tempted to stamp an audit ID into message metadata and filter on it later. That door is closed here, and it's the wrong door anyway — metadata lives in the same mutable mailbox you're trying to audit If you've used any grant-scoped Nylas endpoint, there's nothing new on the data plane. An Agent Account is just a grant with a grant id . It addresses the same /v3/grants/{grant id}/ routes as any other grant — Messages, Threads, Folders, Attachments, the lot. Same auth header, same payloads. The audit subsystem hangs off two of those routes plus one app-level webhook. So the spine of this post is small: message id and thread id plus the payload. message.created webhook, fetch the full message and record it. thread id .That's it. Everything else is plumbing around making the store immutable. You need a registered domain a custom domain, or a Nylas .nylas.email trial subdomain and an Agent Account on it. New domains warm over roughly four weeks before they're at full sending reputation, so provision early. Provision via the API with POST /v3/connect/custom : curl --request POST \ --url 'https://api.us.nylas.com/v3/connect/custom' \ --header 'Authorization: Bearer