README file from
GithubMailstone
🇬🇧 English · 🇩🇪 Deutsch
Mailstone turns a mail folder on your server into notes in your vault — the server decides what becomes a note, and reading never marks a message as read.
Triage stays where your mail already lives: move a message into one designated IMAP folder — from your phone, from webmail, from a mail rule — and the next sync writes it into the vault as a Markdown note, with the original .eml beside it. Sending uses the same account over SMTP, and the plugin delivers iMIP calendar invitations on behalf of the sister plugin calendar-notes.
Features
- Mail as notes. A server-side folder decides what becomes a note. The Message-ID is the identity, and the original
.emlstays next to the note, so everything derived from it can be rebuilt. - A panel in the right sidebar. Per account: what the last run did, when the next one is due, the counters that are not zero, the error in plain words — and a button to synchronise now, for one account or all of them. The last run survives a restart.
- An inbox tab. The last 100 messages of your inbox, with a tick for everything that is already a note. Three actions per row: Move to vault and Archive (both server-side, both after a confirmation) and — once TaskNotes is installed — Create task.
- Commands on a mail note. Re-render from the
.eml, relink threads, extract an attachment, reply in your external mail client, create a TaskNotes task. Each shows a preview before it writes. - Import without a server. Import .eml files from a vault folder turns
.emlfiles you already have into notes — no account needed. - Sending. SMTP through the same account, including iMIP invitations for
calendar-notes. Other plugins can send through Mailstone too, after you confirm each one once. - Reading never marks anything as read. Listing, previewing and syncing use
EXAMINEandBODY.PEEK; moving a message carries its flags along. Another tool that keys off "unread" is not disturbed. - Mobile: read what is already synced. Synchronised notes are ordinary Markdown notes on mobile. Sync, sending and the inbox tab need a network layer mobile Obsidian does not provide and stay off there.
Requirements
- Obsidian 1.13.0 or newer. Desktop for everything; mobile only reads notes that a desktop already synchronised.
- An IMAP/SMTP account you can reach with an app password. Providers that require OAuth (Gmail with 2FA, Microsoft 365) are not supported — there is no OAuth flow.
- A folder on the mail server that acts as the allowlist (default name
Vault), and a second one for the archive. Anything you file in the allowlist folder becomes a note; nothing else is touched. - TLS is not optional. Certificate checking cannot be turned off, and plaintext authentication without TLS is refused.
Install
Community Plugins
Listing in the Community Plugins directory is pending review. Once it is through: Settings → Community plugins → Browse → "Mailstone". Until then use one of the ways below.
AnySource Sideloader
AnySource Sideloader installs and updates plugins from any git forge. Subscribe to this catalog once:
https://git.jkaindl.de/jkaindl/obsidian-catalog/raw/branch/main/catalog.json
Mailstone then appears in the sideloader's plugin list and updates like any other plugin, every download checksum-verified.
Manual
Download main.js, manifest.json and styles.css from the latest release into <vault>/.obsidian/plugins/mailstone/, then enable the plugin in Settings → Community plugins. Updates then have to be repeated by hand.
BRAT (beta)
Add johannes-kaindl/mailstone in BRAT.
From source
git clone https://git.jkaindl.de/jkaindl/mailstone
cd mailstone && npm install && npm run build
# main.js manifest.json styles.css → <vault>/.obsidian/plugins/mailstone/
npm run gate runs the full check suite (lint, type checks, unit and integration tests, purity check, build). npm run smoke:e2e is a maintainer-only check against a running Obsidian with TaskNotes installed; it is deliberately not part of gate.
Usage
- Set up an account. Settings → Mailstone → Add account: IMAP and SMTP host, port and TLS mode, username, an app-specific password, at least one identity, and the folder names as your IMAP server shows them. Test SMTP connection checks host, TLS and login without sending anything.
<img src="https://raw.githubusercontent.com/johannes-kaindl/mailstone/main/docs/images/relink-preview.png" width="820" alt="The "Review before writing" dialog of the Relink mail threads command: one note gets a wikilink in in_reply_to, shown as Before and After, with Cancel and Apply.">
Configuration
Click the preview for the full-size image
Settings → Mailstone. Per account (Add account / Edit):
| Setting | What it does | Default |
|---|---|---|
| IMAP / SMTP: Host, Port, TLS | Implicit (usually 993/465) or STARTTLS (143/587) |
— |
| Username, Password | The password lives in Obsidian's secret storage, never in data.json or the vault |
— |
| Identities | Addresses you may send from; one is the default | — |
| Folders: Inbox | The folder the inbox tab lists | INBOX |
| Folders: Allowlist | The folder that decides what becomes a note | Vault |
| Folders: Archive | Where Archive moves a message | Archive |
| Folders: Sent | Where a sent copy is filed; empty turns the copy off | Sent |
| Sync enabled / Sync interval (minutes) | Automatic sync per account | on / 5 |
Global settings:
| Setting | What it does | Default |
|---|---|---|
| Notes folder | Where mail notes are created, in a subfolder per year | Mail |
| Subfolder per year | Turns the year subfolders off | on |
| Filename template | Placeholders {date}, {time}, {slug}, {year} |
{date}-{time}-{slug} |
| Extra fields for new mail notes | Fields written once into a note's front matter when it is first created, for example status: open |
none |
| Allowed note-creation values | Values accepted for the fields written at creation | mail |
| Plugins allowed to send | Plugins that send through Mailstone without asking; revoke one to be asked again | none |
| Open the panel at startup | Opens the sidebar panel when Obsidian starts | off |
| Debug log | Writes the IMAP/SMTP dialogue to the developer console, passwords masked | off |
| Language | Interface language | Automatic |
Documentation
- Documentation index
- Getting started — from installation to your first mail note
- Troubleshooting — the error messages, what causes them, what to do
How it works
The server decides, not the plugin. A folder on the mail server is the allowlist. Sync reads it, and every message in it becomes a note — no rules engine, no filters in the plugin.
The Message-ID is the identity. It survives re-downloads, folder moves and renamed files. The .eml next to each note is the fidelity surface: front matter, rendered body and attachments can be rebuilt from it, so a formatting change never costs you data.
Notes are merged, not overwritten. Your own text lives outside a marked zone (%% mailstone:begin %% … %% mailstone:end %%) and is compared by hash before any write. If you edited the managed zone, the write is refused rather than silently applied. Mailstone never deletes a note: a message that leaves the folder is marked detached, and putting it back reattaches it.
Two kinds of IMAP session, enforced by the compiler. The read path cannot call SELECT or UID MOVE; those live on a separate session used only by the inbox actions. That is why "reading never marks as read" is a property of the type system, not a rule someone has to remember. Architecture and conventions are in AGENTS.md.
Contributing
Issues and pull requests on GitHub; the canonical repository is on git.jkaindl.de. Test-driven (npm test, full check with npm run gate); larger features go through brainstorm → spec → plan → TDD. See AGENTS.md.
License
- Code: AGPL-3.0-or-later (
LICENSE; dual-license option inLICENSING.md). - Docs/Text: CC BY-SA 4.0 (
LICENSE-DOCS).
Copyright © 2026 Johannes Kaindl.