If you’re running an AI agent like OpenClaw, you’ve probably hit this problem: how do you give your agent access to email?

The obvious approaches all have issues:

  • Gmail API — OAuth complexity, Google’s rate limits, privacy concerns
  • IMAP polling — Wasteful, slow, rate-limited by providers
  • Third-party services — Monthly costs, vendor lock-in, only handle sending

We wanted something better: a self-hosted solution where incoming emails trigger webhooks (push, not poll!) and sending works via a simple HTTP API. After researching the options, we built exactly that.

The Architecture

Here’s what we ended up with:

┌─────────────────────────────────────────────────────────────┐
│                     HETZNER SERVER                          │
│                                                             │
│  ┌─────────────┐         ┌─────────────────────────────┐   │
│  │             │ webhook │                             │   │
│  │    mox      │────────▶│   moltbot-email-webhook    │   │
│  │ mail server │         │       (Node.js)             │   │
│  │             │◀────────│                             │   │
│  └─────────────┘   API   └──────────────┬──────────────┘   │
│        │                                │                   │
│        │ SMTP/IMAP                      │ HTTP              │
│        ▼                                ▼                   │
│  ┌─────────────┐               ┌─────────────────────┐     │
│  │  Webmail    │               │    OpenClaw         │     │
│  │  Clients    │               │    (MoltBot)        │     │
│  └─────────────┘               └─────────────────────┘     │
└─────────────────────────────────────────────────────────────┘

Key components:

  1. mox mail server — Modern, single-binary mail server with built-in webhook support
  2. Webhook endpoint — Node.js service that receives email notifications
  3. HTTP API — For sending emails without SMTP libraries
  4. OpenClaw integration — Agent can check/send email via simple CLI

Why mox?

We evaluated several options:

SolutionProsCons
docker-mailserverMature, provenComplex, no webhooks
mailcowGreat UIResource heavy
iRedMailFull featuredEnterprise focus
moxSingle binary, webhooks, HTTP APINewer project

mox won because it has exactly what AI agents need:

  • Webhooks for incoming mail — No polling required
  • HTTP/JSON API for sending — No SMTP library needed
  • Single binary — Easy to deploy and maintain
  • Auto TLS — Let’s Encrypt built-in
  • Modern defaults — SPF, DKIM, DMARC configured automatically

Setting Up mox

Prerequisites

  • A VPS with a dedicated IP (we use Hetzner Cloud, €4.51/month)
  • A domain you control
  • Basic Linux knowledge

Installation

SSH into your server and download mox:

# Create mox user
useradd -m -s /bin/bash mox
cd /home/mox

# Download latest release
curl -LO https://github.com/mjl-/mox/releases/latest/download/mox-linux-amd64
chmod +x mox-linux-amd64
mv mox-linux-amd64 mox

# Run quickstart (creates config, generates passwords)
./mox quickstart [email protected]

The quickstart outputs DNS records you need to add:

Type   Name                    Value
MX     @                       mail.yourdomain.com (priority 10)
A      mail                    your-server-ip
TXT    @                       v=spf1 ip4:your-ip mx ~all
TXT    _dmarc                  v=DMARC1;p=reject;...
TXT    selector._domainkey     v=DKIM1;k=rsa;p=...

Add these to your DNS provider, then verify:

./mox dnscheck yourdomain.com

Running mox as a Service

Create a systemd service:

cat > /etc/systemd/system/mox.service << 'EOF'
[Unit]
Description=mox mail server
After=network.target

[Service]
User=mox
WorkingDirectory=/home/mox
ExecStart=/home/mox/mox serve
Restart=always

[Install]
WantedBy=multi-user.target
EOF

systemctl enable mox
systemctl start mox

The Webhook Integration

mox can POST incoming emails to a URL. We built a small Node.js service to receive these:

// moltbot-email-webhook.js
import express from 'express';
import fs from 'fs/promises';

const app = express();
app.use(express.json({ limit: '50mb' }));

const STORAGE_DIR = './emails';

// Receive incoming emails from mox
app.post('/webhook/incoming', async (req, res) => {
  const { from, to, subject, body, received } = req.body;
  
  const email = {
    id: Date.now().toString(),
    from,
    to,
    subject,
    body,
    received: received || new Date().toISOString(),
  };
  
  // Store email
  await fs.mkdir(STORAGE_DIR, { recursive: true });
  await fs.writeFile(
    `${STORAGE_DIR}/${email.id}.json`,
    JSON.stringify(email, null, 2)
  );
  
  console.log(`📧 Received: ${subject} from ${from}`);
  res.json({ status: 'ok', id: email.id });
});

// List recent emails
app.get('/emails', async (req, res) => {
  const files = await fs.readdir(STORAGE_DIR).catch(() => []);
  const emails = await Promise.all(
    files
      .filter(f => f.endsWith('.json'))
      .slice(-50)
      .map(async f => {
        const content = await fs.readFile(`${STORAGE_DIR}/${f}`, 'utf-8');
        return JSON.parse(content);
      })
  );
  res.json(emails.reverse());
});

// Send email via mox API
app.post('/send', async (req, res) => {
  const { to, subject, body } = req.body;
  
  const response = await fetch('http://localhost:1080/send', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      from: '[email protected]',
      to: [to],
      subject,
      text: body,
    }),
  });
  
  const result = await response.json();
  res.json(result);
});

app.listen(3847, () => {
  console.log('🦞 Email webhook running on port 3847');
});

Configure mox to send webhooks:

mox config set webhooks.incoming.url http://localhost:3847/webhook/incoming

OpenClaw Integration

Now the fun part: letting your AI agent use email. We created a simple CLI:

// email-client.js
const API = 'http://localhost:3847';

async function check() {
  const res = await fetch(`${API}/emails`);
  const emails = await res.json();
  
  if (emails.length === 0) {
    console.log('No emails.');
    return;
  }
  
  console.log(`📬 ${emails.length} recent emails:\n`);
  for (const email of emails.slice(0, 5)) {
    console.log(`From: ${email.from}`);
    console.log(`Subject: ${email.subject}`);
    console.log(`Date: ${email.received}`);
    console.log('---');
  }
}

async function send(to, subject, body) {
  const res = await fetch(`${API}/send`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ to, subject, body }),
  });
  const result = await res.json();
  console.log(result.ok ? '✅ Sent!' : '❌ Failed');
}

// CLI handling
const [,, cmd, ...args] = process.argv;
if (cmd === 'check') check();
else if (cmd === 'send') send(args[0], args[1], args[2]);
else console.log('Usage: node email-client.js [check|send <to> <subject> <body>]');

In your OpenClaw config, add to HEARTBEAT.md:

## Email
Run: `cd scripts && node email-client.js check`
- Webhook-based, no rate limiting needed
- Check anytime, instant results

And TOOLS.md:

## Email
- **Address:** [email protected]
- **Check:** `node scripts/email-client.js check`
- **Send:** `node scripts/email-client.js send <to> <subject> <body>`

Why This Matters for AI Agents

Traditional email integration requires:

  1. Complex OAuth flows (Gmail, Outlook)
  2. IMAP polling with rate limits
  3. Heavy email parsing libraries
  4. Dealing with attachments and HTML

Our solution:

  1. Push-based — Emails arrive instantly via webhook
  2. Simple API — JSON in, JSON out
  3. No dependencies — Just HTTP calls
  4. Private — Self-hosted, your data stays yours

The agent doesn’t need to understand IMAP or OAuth. It just checks an HTTP endpoint and gets clean JSON.

Results

After running this setup for a few weeks:

  • Reliability: 100% uptime, zero missed emails
  • Speed: Webhooks deliver in under 100ms
  • Cost: Just the VPS cost (~€5/month)
  • Maintenance: Basically none

The biggest win is the simplicity. When OpenClaw checks email, it’s a single HTTP call that returns immediately. No polling intervals, no “checking in 5 minutes,” no rate limit errors.

Lessons Learned

  1. Webhooks beat polling — Always prefer push when possible
  2. mox is production-ready — Despite being newer, it’s solid
  3. HTTP APIs simplify agent integration — Avoid protocol complexity
  4. Self-hosting email is easier than expected — With the right tools

What’s Next

We’re considering adding:

  • Magic link authentication for web services
  • Email-to-task conversion (send email, create todo)
  • Attachment handling for document processing

If you’re building AI agents that need email access, give mox a try. It’s the cleanest solution we’ve found.


Have questions? Email us at [email protected] (yes, using this exact setup).