You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
export_thread — a thread to a local file. Markdown for people (one section per message
with headers, sender authentication and attachment list, each body in a code fence chosen longer
than any backtick run in it, so the mail text cannot close the fence and render as part of the
document; From, To, Subject and attachment names as inline code, so a preview cannot turn a
subject into a tracking image or a sender name into a link; HTML-only mail is reduced to text) or
JSON as get_thread returns it. Both formats strip the hidden characters every tool result is
stripped of. The thread is fetched before any directory is created. For
keeping or handing on a conversation, or reading a long one without loading it into the context.
Manage tier, like download_attachment, and under the same path rules: the path check is now one
shared function, so MAILWARDEN_DOWNLOAD_DIR fences both, never overwrites for both, and the --http startup warning names both.
follow_ups — who is waiting on whom. Threads whose last message is yours and has gone
unanswered for nudgeAfterDays (default three), and inbox threads whose last message came from a
person, oldest first. Read tier, no body fetched. The search index only proposes candidates:
each thread is decided on its last message and that message's live labels, so a thread the index
still lists under in:inbox after it was archived is dropped, as in search. Drafts and trashed
or spam messages are never the last word, mail whose own headers mark it as a newsletter or as
automated is not "waiting on me", a note to the account's own address is not "waiting on them" (To and Cc both count, as do the
spellings Gmail delivers to the same inbox: +tags, dots, googlemail.com),
and a thread without a recorded date is left out rather than given an invented age. The two sides
are fetched one after the other, so the call never runs more fetches at once than search does. Prompted by the follow-up views in other Gmail MCP servers.
An exact undo for bulk_modify.undo: true reads every affected thread's labels live
before writing and returns undo, the per-message inverse of the change: what each message lost
goes back, what it gained comes off, and a message that was already in the target state is left
out. The new undo_bulk_modify tool replays that plan. Swapping add and remove is not an
undo: archive a set of which some threads were already archived, and the swapped call puts those
in the inbox for the first time. The plan is built for up to 500 messages, because it carries
every message id through the context. With undo: true nothing is written unless the plan can be
built: more messages than that, or a prior state that could not be read, is an error before the
first write, and before any label named in add is created. undo_bulk_modify takes label ids only, so an unknown name cannot be created instead
of restored, and with verify reads each thread back once. A label the bulk change created is
taken off again but stays in the mailbox, empty. Adding and removing the same label in one call
is refused. Prompted by @agentcomms/gmail-mcp, which returns an undo with every bulk change.
A plugin icon. A shield with an envelope inside, white strokes on a slate ground, drawn on a
1000-unit grid: assets/icon/icon.svg is the source, .claude-plugin/icon.png the 1024 px render
the plugin directory looks for, and assets/icon/ holds the other sizes, two transparent glyphs
and a favicon set (see assets/icon/README.md). None of it ships in the npm package. The directory's
check listed the missing icon as a warning; the listing otherwise shows a blank tile.
Changed
docs/SETUP.md explains Google's new "AI-powered agent" checkbox on OAuth clients. It is a
self-declaration that grants nothing and that mailwarden does not need: it gates Google's own
hosted Workspace MCP servers, and mailwarden talks only to the Gmail REST API. The guide
recommends ticking it because it is the accurate answer, and warns that Google fixes the setting
for existing clients after a cut-over date.
The Claude Code plugin pins the package it launches..claude-plugin/plugin.json now starts npx -y mailwarden@<version> instead of npx -y mailwarden, carries a version of its own, and
the setup skill's --auth/--check commands name the same version. Anthropic's plugin directory
held the submission of 15 August under its policy against unpinned launchers: a reviewer approves
one revision of the code, and an unpinned npx would run whatever npm serves later. The pin is
kept current by scripts/sync-version.mjs on every npm version, the same step that already
syncs server.json, and a test fails the build when the manifest, the skills and package.json
disagree — a version written in three files is a version that drifts. A claude mcp add setup is
unaffected; this is about the plugin alone.
Fixed
"The only other server that can refuse to send" was no longer true. README and SECURITY.md
said it of aaronsb; agentcomms can be set to a never send policy as well. Noticed by
csitte.at while taking over the new column, who had the same sentence.
The comparison table understated Google's own Gmail MCP server on structured outputs.
Its tool reference documents an output schema for every tool, and has since July; the reading of
3 September 2026 recorded none, so the README cell said "not offered" and docs/ROADMAP.md said
no server in the table declares one on more than a single tool. Both are corrected after a full
re-read on 13 October 2026, which also found an eleventh tool (create_label) the old list missed.
No other Google cell moves. The a-bonus column is brought forward to d9e9bb21 in the same pass;
no cell moves there. The table's date marker moves to 10 October 2026, its oldest column check.
The README no longer calls sender authentication unique.@agentcomms/gmail-mcp, first
published on 18 September 2026, reads SPF, DKIM and DMARC from Authentication-Results as well,
found in a landscape scan on 13 October 2026 and checked in its source. Snooze and search
re-verification remain without a counterpart in anything we have read.
The comparison table has a column for agentcomms (@agentcomms/gmail-mcp), read at 01cee751 on 13 October 2026. It earns the column on two rows: it reads Authentication-Results
pinned to Gmail's own report, and its bulk changes return an exact per-message undo. Its npm reach
passed klodr's within a month of its first release. The cells record that it sends behind a
per-message approval whose default is a yes in the conversation, and that its bulk path takes ids,
not a query.
npm run mcpb failed on a Windows machine whose Node lives under a path with a space. The
spawn helper in scripts/lib/run.mjs quoted every argument for the shell but not the command
itself, so process.execPath = C:\Program Files\nodejs\node.exe reached cmd.exe as C:\Program, and the first mcpb validate step died before the bundle existed. It had never
shown because every earlier release was cut from a machine whose Node sits in a space-free path.
The command is now quoted by the same rule as the arguments. The 0.22.1 bundles were built on the
clean tag checkout through the 8.3 short path (C:\PROGRA~1), so they are unaffected; the fix
is for the next machine.
Security
Sender authentication reads Gmail's own report only.authentication on every message now
comes from the topmost Authentication-Results header whose authserv-id is mx.google.com; a
report under any other id is counted in otherReports and never read. Until now the first report
was read whatever its id. That was right wherever Gmail had written one and wrong exactly where it
had not: a message with no Gmail report but a forged one of its own had the forgery reported as
its verdict, with only authservId to give it away. Such a message is now unchecked. Measured
on 13 October 2026 in two mailboxes before the change: every received message's first report came
from mx.google.com, and the only messages without one were sent mail, so no real verdict is
lost. Prompted by @agentcomms/gmail-mcp, which reads the same header under this rule. Not
covered, and documented as such: mail that never passed Gmail's inbound server (a POP fetch, an
app's insert) may carry no Gmail report, and a forgery claiming mx.google.com is then read.
New dkimAligned field. Whether a passing DKIM signature was made by the From domain or a
parent or child of it — relaxed alignment approximated by the domain tree, which is sound because
a signing domain has to publish its key in its own DNS. dkim: "pass" alone says only that
someone signed. Results written with spaces around =, which RFC 8601 allows, are read too.
Absent when DKIM did not pass, a domain is unknown, or the two are sibling
subdomains: news.bank.example/mail.bank.example are aligned and a.co.uk/b.co.uk are not,
and without a public-suffix list they look alike — so the field says nothing rather than a false that would read as suspicious.