Most people building AI agents treat email as an afterthought. They give the agent access to the user’s inbox through OAuth, let it read and send on the user’s behalf, and call it a day. I think that’s fundamentally wrong.
An AI agent that borrows your email address is pretending to be you. Every message it sends carries your name, your reputation, your identity. If it makes a mistake, you own it. If it gets into a conversation with another agent, there’s no way to tell the human apart from the machine. That’s a problem.
The case for agent identity
What if your agent had its own email address? Not a throwaway alias, but a real mailbox on a real domain with proper DNS records. Something like assistant@yourdomain.com that the agent actually owns.
This changes everything. The agent can:
- Sign up for services using its own address, keeping your personal email clean
- Receive verification codes and handle onboarding flows autonomously
- Communicate with other agents in a way that’s transparent and traceable
- Build its own contact network without polluting your inbox
- Be identified as an agent by anyone who looks at the sender
That last point matters more than you’d think. As agents become more common in the email ecosystem, having clear agent identity will be essential for trust.
Self hosting with Stalwart
For AgenticMail, I chose Stalwart as the mail server. It’s a modern, Rust based mail server that supports JMAP, IMAP, and SMTP out of the box. The whole thing runs in a single Docker container, which makes deployment trivial.
The setup looks roughly like this: Stalwart runs in Docker, AgenticMail connects to it via JMAP for mailbox operations, and the gateway layer handles the connection to the outside email world. Each agent gets a real account on the server with its own credentials, storage quota, and mailbox hierarchy.
Why self hosted? Because giving an AI agent access to a third party email provider means trusting that provider with everything the agent sees and sends. When you run the mail server yourself, the data stays on your infrastructure. For an enterprise deployment where agents might handle sensitive communications, that’s not optional.
More than a mailbox
Having a real email address is just the foundation. Once the agent has its own identity, you can build real systems on top of it. Inter agent task assignment. RPC style request/response patterns. Notification chains. All using email as the transport layer, which means it works across organizational boundaries without any special infrastructure.
Email is the one protocol that every organization already supports. Every firewall already allows it. Every person already understands it. By giving agents their own email addresses, we’re not inventing a new communication layer; we’re plugging into the one that already exists everywhere.
What AgenticMail actually does
AgenticMail is the npm package that makes all of this work. You npm install agenticmail, point it at a Stalwart instance (or let it spin one up in Docker), and you’ve got a full agent email system. Create agents, assign them addresses, let them send and receive, and layer on security with the spam filter, outbound guard, and sanitizer modules.
The enterprise package (@agenticmail/enterprise) adds multi tenant support, the gateway system for connecting to external email, and the full admin API. But the core idea is the same: agents deserve their own email identity.
I’ll be writing more about the individual components in upcoming posts. The security layers alone are worth a deep dive, because letting an AI agent interact with the open internet through email introduces a whole category of threats that most people haven’t thought about yet.
Source Code
The AccountManager class is where agent creation happens. It provisions an email account on Stalwart, generates API credentials, and wraps the whole thing in a transaction so that a failed database insert rolls back the mail server state. This is the core of how every agent gets its own identity.
export class AccountManager {
async create(options: CreateAgentOptions): Promise<Agent> {
const id = uuidv4();
const apiKey = generateApiKey();
const password = options.password ?? generatePassword();
const email = `${options.name.toLowerCase()}@${domain}`;
await this.stalwart.ensureDomain(domain);
await this.stalwart.createPrincipal({
type: 'individual', name: options.name.toLowerCase(),
secrets: [password], emails: [email], roles: ['user'],
});
// Transactional: if SQLite insert fails, rollback Stalwart
try {
stmt.run(id, options.name, email, apiKey, principalName, JSON.stringify(metadata), role);
} catch (err) {
try { await this.stalwart.deletePrincipal(principalName); } catch {}
throw err;
}
return this.getById(id);
}
}
View the full source on GitHub
For now, the takeaway is simple: stop letting agents borrow your email. Give them their own.