station · ivanmisic.net log in
§01 AI & Tools ↵ back to ai & tools
No API Required

Capturing Email and Calendar Without a Mailbox API

Microsoft Graph and IMAP were off the table, so I used Power Automate, OneDrive sync, and one 15-minute scheduled task to pull email and calendar into a local inbox.
Published
Reading
11 min · 2,136 words

Your email and calendar are the richest record of your work week, and usually the most locked down. In the overview of my Obsidian and Claude setup I mentioned getting both into a local inbox with no API access at all. This is how, in enough detail to copy.

The obvious routes are closed

The clean way to read a corporate mailbox from a script is an API: Microsoft Graph, or plain old IMAP. In a lot of workplaces neither is realistic for a personal project. Graph wants an app registration and admin consent. IMAP is often switched off. The front door is locked, and it's locked for good reasons.

The side door is a tool your company is probably already paying for. Power Automate is Microsoft's own workflow automation, it has blessed connectors to your mailbox and calendar, and it can write files to your OneDrive. OneDrive syncs those files to your laptop. From there, a tiny scheduled task drops them into the vault. Three dumb pieces, none of which asks for any permission you don't already have.

The shape of it

The whole path runs one direction, mailbox to local folder:

The capture path as five stages left to right: mailbox, Power Automate, OneDrive, a timer, and the vault folder, with a branch off OneDrive into a Processed folder

Every hop is dumb and independent. If OneDrive is slow, the flow still runs. If the laptop is off, the files wait in the cloud. Nothing holds a connection open, so nothing has a connection to lose. That property is the whole reason this beats a "proper" integration, and I'll come back to it.

Flow 1: capture the mail you care about

Received mail is captured by flag, not by firehose. I don't want every email in the vault, I want the ones that matter, so the flow triggers on When an email is flagged (V3) in the Inbox. I flag a message in Outlook, the flow fires, fetches the full email, converts the HTML body to plain text, and writes a .txt into EmailCapture/Vault. Then it unflags the message so it can't fire twice. Any attachments go alongside it in EmailCapture/Vault/Attachments, numbered so two files called report.pdf can't collide. If I tag the email with an Outlook category first (VIP, Follow Up, Waiting), the flow captures that too, and falls back to Uncategorized when I haven't.

The file the Compose step assembles comes out like this:

Type Category: VIP
Type From:  sender@example.com
Type To:  you@example.com
Type CC:
Type Subject:  RE: Q2 Budget Review
Type Date:  2026-03-06T14:30:00Z
Type ConversationId:  AAQkAGI2...

Could you review the attached budget before Thursday...

That ConversationId is Outlook's thread identifier, captured so the vault can group a reply chain with certainty instead of guessing from the subject line. The Type prefix on every header is a Power Automate quirk, and I'll come back to it.

Flow 2: capture everything you send

Sent mail is the opposite. I want all of it with no effort, so that flow triggers automatically on every new item in Sent Items. A condition filters out the automatic meeting accept and decline replies so they don't become noise, then it converts the body to text and writes a .txt into EmailCapture/Sent. No flag, no thought.

That condition matches on the subject prefix, so it needs every language your calendar replies arrive in. Mine checks eleven prefixes across English, German, and Croatian, because a Declined: filter does nothing about an Abgelehnt: or an Odbijeno:. If your work spans more than a couple of countries, that list only grows, and every language you miss is a category of noise you'll be deleting by hand later. Check your own sent folder before you assume one covers it.

The sent file uses plain headers, and the From field comes out empty:

From:
To: colleague@example.com
CC:
Subject: RE: Some Subject Here
Date: 2026-03-06T14:30:00Z
ConversationId: AAQkAGI2...

Email body in plain text...

The two-formats gotcha

Look at the two examples. Received mail prefixes every header with Type, sent mail doesn't, and sent mail has an empty From. That isn't a choice, it's how the two triggers serialize their data. Instead of fighting Power Automate into agreement, I let the parser downstream read both shapes. The capture layer has exactly one job: get each file into the right folder. That empty From on sent mail is the reason the bridge script matters later.

Flow 3: the senders you can't afford to miss

Flagging works on the days I'm reading my inbox. It fails on the days I'm not, and those are exactly the days something from the wrong person sits unread until Thursday. So the third flow watches people instead of messages.

The tagging half isn't Power Automate at all. An ordinary Outlook rule puts a VIP category on anything from the senders I list, the moment it arrives. Then the flow wakes up every 15 minutes and asks the mailbox for category:VIP NOT category:VIP-Captured, takes up to ten at a time, writes each one out the way Flow 1 does, and stamps the message with a second category, VIP-Captured.

That second category is the trick. Flow 1 can unflag a message to stop it firing twice, but this one can't clear the VIP tag, because I still want it there when I go looking. So it adds a marker instead, and the search query filters on it. There's no list of processed IDs anywhere, and if I ever want a message recaptured I delete one category by hand.

One difference from Flow 1 that matters downstream: VIP mail lands in its own EmailCapture/VIP/Vault folder, so the bridge script treats it as a separate source. Otherwise it behaves the same, attachments included.

And the calendar

The calendar is one more flow, scheduled to run every 30 minutes through the workday. It uses Get calendar view of events (V3) for today's range, a Select to keep the fields I care about (subject, start, end, organizer, attendees, online meeting link), and a Create file that writes yyyy-MM-dd-calendar.json into EmailCapture/Calendar. Because it overwrites the same day's file on each run, the calendar is always one fresh snapshot instead of a pile of duplicates.

The bridge: one scheduled task

The files are now in OneDrive, which syncs to the laptop. The last hop is a small PowerShell script on a 15-minute timer. It walks each capture folder in turn: received mail into the inbox as-is, VIP mail the same way from its own folder, sent mail with a SENT- prefix, and the calendar snapshot refreshed. The core of it, trimmed to three of the four:

$Sent     = "$env:USERPROFILE\OneDrive\EmailCapture\Sent"
$Received = "$env:USERPROFILE\OneDrive\EmailCapture\Vault"
$Calendar = "$env:USERPROFILE\OneDrive\EmailCapture\Calendar"
$Inbox    = "$env:USERPROFILE\Obsidian\WorkVault\00-Inbox"

# Sent mail -> inbox, tagged so the direction survives
Get-ChildItem $Sent -Filter *.txt | ForEach-Object {
    Copy-Item $_.FullName (Join-Path $Inbox "SENT-$($_.Name)")
    Move-Item $_.FullName (Join-Path "$Sent\Processed" $_.Name)
}

# Received mail -> inbox as-is
Get-ChildItem $Received -Filter *.txt | ForEach-Object {
    Copy-Item $_.FullName (Join-Path $Inbox $_.Name)
    Move-Item $_.FullName (Join-Path "$Received\Processed" $_.Name)
}

# Calendar -> overwrite today's snapshot
Get-ChildItem $Calendar -Filter *-calendar.json | ForEach-Object {
    Copy-Item $_.FullName (Join-Path $Inbox $_.Name) -Force
}

The full version adds a -2 suffix when a filename already exists and rotates its own log. But that is the whole idea: copy, mark as done, move on.

The Move-Item into Processed is doing more work than it looks like. Once a file has been copied into the vault it leaves the capture folder entirely, so the next run has nothing to reconsider, the same email can't arrive twice, and the OneDrive folder doesn't quietly grow forever. Every file gets exactly one trip, and the originals are still sitting in Processed if you ever need to prove what came in.

That SENT- prefix is the dumbest and most useful line in the file. Power Automate hands me sent mail with an empty From, so the content alone can't tell me which way a message went. Four characters added at copy time settle it for good, and every step downstream just reads the filename.

Put it on a timer

Register the script as a scheduled task that fires every 15 minutes while you're logged in:

$Action  = New-ScheduledTaskAction -Execute "powershell.exe" `
    -Argument "-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File C:\path\to\Pull-Emails.ps1"
$Trigger = New-ScheduledTaskTrigger -Once -At (Get-Date).Date `
    -RepetitionInterval (New-TimeSpan -Minutes 15)
Register-ScheduledTask -TaskName "PullEmails" -Action $Action -Trigger $Trigger `
    -Description "Copies captured mail and calendar into the vault inbox"

If the console window flashing every fifteen minutes bothers you, and it will, wrap the call in a one-line .vbs launched with wscript.exe so it runs fully hidden. Tiny thing, real quality-of-life gain.

If your vault already lives in OneDrive

Then you can skip most of this. Point the Power Automate Create file step straight at the vault's inbox folder and the files arrive on their own, no scheduled task anywhere.

I kept the task, and the reason is the three small things it does on the way past: the SENT- prefix, the Processed move, and the duplicate-name suffix. Write directly into the inbox and you lose all three, which means sent and received mail become indistinguishable and nothing ever gets swept out of the capture folder. If you don't need that distinction, take the shorter path. I did need it, so I pay one scheduled task for it.

What the AI actually sees

Worth being exact here, because "my work email goes into a folder an AI reads" deserves a straight answer.

Everything described so far moves your real mail. The file that lands in your inbox has real names and real addresses in it, and nothing is masked on this leg. What it has going for it: nothing leaves your company's tenant, your OneDrive, your disk. The mail was already sitting in all three.

The masking happens one step later, before anything reaches a model. A script swaps addresses, phone numbers, and the other patterns that scan as private for tokens, and keeps the real values in a local map the model never gets handed. I went through that in the overview of the setup. It lowers what gets sent rather than pretending to eliminate it, and it's honest about the gap: subject lines and meeting titles still go out roughly as written.

So the capture layer is not the privacy layer, and this post only covers the first one.

Why text files instead of a real integration

This looks primitive next to a proper API client, and that is the point. A token-based integration is a thing that breaks. Tokens expire, scopes change, rate limits bite, a refresh quietly fails overnight and the sync is down until you happen to notice. A folder of text files has none of those failure modes. Each email is one file. Either it copied or it didn't, and if it didn't, the next run grabs it. Keeping the transport alive is OneDrive's job, and OneDrive is very good at its job.

What this won't do

A few honest limits:

  • It needs Power Automate, which usually means a Microsoft 365 business plan, and some licenses cap how many flow runs you get per day.
  • It isn't real-time. Worst case, a message waits about 15 minutes before it reaches the inbox. Fine for a once-a-day review, not fine for a live assistant.
  • The scheduled task is Windows. The same pattern runs on a Mac or Linux box with cron and the OneDrive client; the script is just shell instead of PowerShell.
  • Check your own policy. Exporting mail to files, even your own mail, may or may not be allowed where you work. This is a know-the-rules situation, not an ask-forgiveness one.

The boring part is the important part

None of this is clever. It's a flow, a sync folder, and a timer, held together by a four-character filename prefix. But it's the piece everything else leans on, because the smartest pipeline in the world does nothing until the data actually shows up. Get the dull part right and the interesting parts get to exist.

I don't think this is the permanent shape of it. My guess is that within a few years the assistant just has a sanctioned connector to your mailbox, IT is comfortable switching it on, and none of this plumbing is anyone's problem. That's a prediction, not a roadmap, and I've been wrong about timelines before. What I'm confident about is the gap in between: right now there's a real distance between what these tools could do with your work context and what your IT department will let them touch. A flow and a sync folder is what half-automation looks like while you wait. I'd rather run the boring version today than wait for the clean one to get approved.

Next: what happens to all of this once it lands, and why most of that pipeline isn't AI at all.

Get Personalized Help

Copy this prompt to ChatGPT, Claude, or your favorite AI assistant. Fill in your details and get guidance tailored to your specific situation.

I read https://ivanmisic.net/blog/ai-tools/email-calendar-capture-without-api and I want to build this email and calendar capture for myself.

Do not build anything yet, and do not open any tabs. Your job in this conversation is to interview me and then write me a set of prompts I will run separately, one per flow, in Claude for Chrome (https://claude.com/claude-for-chrome). I want them separate because building four flows in one browser session is a lot of state to hold, and because I may not want all four.

STEP 1: INTERVIEW ME

Ask all of this in a single message, with your recommended default marked on each, so I can reply "defaults" and move on:

1. Which pieces do I want? Flagged mail capture, sent mail capture, VIP sender capture, calendar snapshot. Give me one line per piece on what I lose by skipping it, and tell me which one to build first if I only ever build one.
2. If I want VIP capture: which senders or addresses count as never-miss?
3. What languages do my meeting accept and decline replies arrive in? Do not assume English only.
4. Is my notes vault already inside my OneDrive folder, or somewhere else on disk?
5. Windows, Mac, or Linux for the final copy step?
6. What should the OneDrive capture folder be called? Default: EmailCapture.

If my answer to any of these is vague, ask once more rather than guessing. Then show me the build order you plan and wait for me to confirm before writing anything.

STEP 2: WRITE ME ONE PROMPT PER PIECE

Each prompt has to work in a brand new Claude for Chrome session with no memory of this conversation. That means each one must restate my actual answers as literal values, not placeholders, and must not say "as discussed earlier". Number them in build order and tell me to test each flow before running the next prompt.

Wrap each generated prompt in its own code block so I can copy them one at a time.

Build the prompts from these specs, adapted to my answers:

FLAGGED MAIL CAPTURE. Trigger "When an email is flagged (V3)" on the Inbox. Get the full message, convert the HTML body to plain text, compose a header block, write a .txt into the capture folder, save attachments to an Attachments subfolder with numbered filenames so two files with the same name cannot collide, then unflag the message so it cannot fire twice. Capture the Outlook category if there is one and fall back to "Uncategorized".

SENT MAIL CAPTURE. Trigger "When a new email arrives (V3)" pointed at Sent Items. Before writing anything, a condition that rejects automatic meeting replies by subject prefix, covering every language I named. List the exact prefixes so I can check them against my own sent folder. Then body to text, write a .txt to the Sent capture folder.

VIP SENDER CAPTURE. Two halves. First, walk me through creating the plain Outlook rule that tags mail from my named senders with a VIP category on arrival, since that half is not Power Automate. Second, a flow on a 15-minute recurrence that searches "category:VIP NOT category:VIP-Captured", takes up to ten at a time, writes them out the same way the flagged flow does, and then assigns a second category "VIP-Captured". Explain why a marker category is used here instead of unflagging.

CALENDAR SNAPSHOT. Scheduled every 30 minutes across the working day. "Get calendar view of events (V3)" for today, a Select step keeping only the fields worth having, a Create file that overwrites the same day's JSON each run so I get one fresh snapshot rather than a pile of duplicates.

THE LAST HOP. Only if my vault is NOT already inside OneDrive: the scheduled task that copies each capture folder into the vault inbox, received mail as-is, VIP mail the same way, sent mail with a SENT- prefix so the direction survives, calendar overwritten, and originals moved to a Processed folder so nothing is copied twice. Match the script to my operating system.
If my vault IS already inside OneDrive: say so, tell me to point the Create file steps straight at the vault inbox instead, and explain what I give up by skipping the script so I can decide for myself.

STEP 3: TELL ME WHAT TO WATCH FOR

Close with a short list of things likely to differ on my screen from any written guide: connectors renamed, actions moved, steps my licence will not allow. And flag anything here that might run into my organisation's policy before I start clicking.

In each generated prompt, remind the assistant that it can see my screen, so where the interface does not match what the prompt describes it should tell me what it actually sees and adapt rather than pushing on.