OpenClaw 3: Inbox Zero on Autopilot

data engineering

My work email through Pinnacle — an Office 365 account — had been quietly accumulating chaos for years. Five hundred unread emails when I started this project. Maybe a thousand. I’d stopped counting. Then, during an Exchange sync that went sideways, the unread count exploded to over 10,000 messages in a few hours. Newsletters, receipts, client threads, automated alerts, spam, everything mixed together.

Dealing with that manually was never going to happen. So I pointed Jax at it and said: figure this out.

Phase One: Reconnaissance

Before doing anything, Jax scanned the inbox to understand what she was dealing with. She read sender domains, subject patterns, and email ages to build a rough taxonomy. The goal wasn’t to read every email — it was to understand the categories.

What she found:

  • A heavy tail of retail and brand newsletters (Boll & Branch, REI, various software tools)
  • Financial statements and bank notices
  • Property management notifications from my rental properties
  • Legal and contract-related correspondence
  • Client project threads
  • Automated system alerts
  • Calendar invites and scheduling threads
  • Amazon orders and shipping notifications
  • LinkedIn and social platform digests
  • News digests (Morning Brew, various industry lists)
  • General junk that somehow escaped the spam filter

Eleven categories. She created a folder structure to match them. This part was fast — maybe 20 minutes to scan and categorize, then another few minutes to create the folders.

The AppleScript + Exchange Problem

Here’s where things got complicated. Moving emails on Exchange through Apple Mail is a client-side operation. You move a message, it shows up in the right folder on your Mac. But Exchange runs its own sync — and if a message gets moved client-side before the server has fully processed it, the sync can resurrect the message back in the inbox.

We hit this repeatedly. Jax would move 200 messages. Exchange would bring 60 of them back. Move them again. Exchange would bring back 40. It was like shoveling against the tide.

The Real Solution: Microsoft Graph API

After fighting with AppleScript and Exchange sync issues for a few hours, it became clear we needed a different approach. The problem was that we were working client-side through Apple Mail, but Exchange Server was the source of truth. We needed to talk directly to Exchange.

That’s where m365 CLI came in. It’s a command-line tool that uses Microsoft Graph API to interact with Office 365 services — email, calendar, contacts, everything — at the server level. No sync conflicts. No resurrection. Just direct manipulation of the data where it actually lives.

But there was a hurdle: OAuth permissions.

Microsoft doesn’t let you just start moving emails around in an Office 365 account. You need to authenticate and grant permissions through their OAuth flow. For Jax, this meant:

  1. Installing the m365 CLI tool (npm install -g @pnp/cli-microsoft365)
  2. Running m365 login to trigger a device code authentication flow
  3. Me opening a browser, going to microsoft.com/devicelogin, and entering the code
  4. Approving the “Microsoft Graph Command Line Tools” app and granting it permissions to read and manage my email
  5. The CLI storing the auth token for future use

The permissions Jax needed:

  • Mail.ReadWrite — to read messages and move them between folders
  • MailboxSettings.Read — to understand folder structures
  • Mail.Send (not used for this project, but granted for future use)

Once authenticated, the m365 CLI gave Jax direct access to my Exchange mailbox through commands like:

m365 outlook message list --folderId inbox
m365 outlook message move --id <messageId> --destinationId <folderId>
m365 outlook folder add --name "Shopping" --parentFolderId <parentId>

The difference was immediate. No more message resurrection. When Jax moved an email using m365, it was gone from the inbox. The operation happened server-side, and Exchange didn’t fight back.

We still set up a cron job to run every 15 minutes — not because of sync issues anymore, but because processing 10,000+ messages in one shot would hit API rate limits. Small batches, frequent runs, and by morning the inbox was clean.

Jax also got smart about which messages to move first. High-confidence matches — @bollandbranch.com → Shopping, @fedex.com → Shipping, bank domain → Finance — went first. Ambiguous senders got flagged for review rather than auto-sorted. That cut the error rate down to nearly zero.

What One Evening Looked Like

The 15-minute cron job ran through the night. By morning, the inbox was down to a manageable number — mostly the genuinely ambiguous stuff that needed a human eye. The noise was gone. The categories were clean.

“@bollandbranch.com → Shopping” — one of the 100+ sender rules Jax derived automatically from scanning patterns. She didn’t need me to tell her. She inferred it from the domain name and email content.

Ongoing Maintenance

The cron job is still running. Every 15 minutes, it checks for new messages that match known patterns and routes them to the right folder. As new senders come in, Jax adds them to the ruleset. The inbox doesn’t accumulate anymore.

What surprised me: I thought this would require a lot of manual rule-setting on my end. Telling Jax which senders go where. Building a spreadsheet of categories. None of that. She inferred the patterns herself from the data. I reviewed her categorization logic once, made a few tweaks, and that was it.

There are still edge cases. A sender that could be either a client or a marketing list. A newsletter from someone I actually know. These go into a “Review” folder and I look at them when I have a few minutes. But the volume in that folder is small — maybe 10-15 messages a day out of what was a constant flood.

What I Actually Got Back

The real win here isn’t the sorted folders. It’s the mental overhead that went away. When I open my inbox now, I see things that need my attention. Not a wall of noise that I have to mentally filter before I can find anything real. The anxiety of the overflowing inbox — that low-level dread that comes from knowing there’s important stuff buried in there somewhere — that’s gone.

My email is now a tool again instead of a weight. That’s worth more than I expected it to be.

The AppleScript-to-m365-CLI pivot is a good example of how these things go in practice. The first approach doesn’t work. You diagnose the problem (client-side vs. server-side operations), find the right tool (Microsoft Graph API via m365 CLI), handle the auth setup once, and the second approach works. Having an AI do the iteration is useful because it doesn’t get frustrated, doesn’t give up, and doesn’t need a break. It just keeps chipping away.

If you’re running OpenClaw and want to replicate this: the m365 CLI is open source and well-documented. The OAuth setup takes about 5 minutes. Once Jax has the credentials, she can manage Office 365 email autonomously — no browser automation, no AppleScript fragility, just direct API calls. It’s one of those cases where using the right tool makes all the difference.