Skip to content

Feature Storage

SkimMail docs edited this page Sep 15, 2026 · 1 revision

English · Tiếng Việt · 中文

Storage settings

Settings ▸ Storage, hidden behind the storage flag from 0.1.0 until it was turned on in 1.14.0. This page covers what the screen actually does today — where cached message bodies live and how to move them, and why the database section next to it is a runbook rather than a button.

What this solves

Two unrelated decisions live on one screen because they are both about where SkimMail keeps its bytes: which blob engine holds cached message bodies (local filesystem, or an S3-compatible bucket), and which database engine holds everything else (SQLite by default, or Postgres/MySQL). This page covers the blob engine in full — it has real, working switch-and-test-and- migrate actions — and the database section honestly, which today is a copy of commands, not an automated migration.

Where it is

Settings ▸ Storage, owner only. The screen carries an "Advanced" badge in its own header — not a technicality, a genuine warning that changing the active engine changes where your data physically lives.

Why this was hidden for eleven releases

The storage flag stayed off from 0.1.0 through 1.13.0 for one specific reason, worth knowing if you read an old screenshot or an old release note: the database section carried a "Migrate database…" button that opened a wizard telling the operator to rebuild SkimMail with -tags postgres first. That was never true for anyone running an official build — every released tarball, .deb, and container image has folded in postgres, mysql and s3 support since 1.4.3 — so the instruction was not merely unnecessary, it described a step a self-hoster with no Go toolchain could not perform at all. 1.14.0 didn't add a missing feature; it stopped a real screen from claiming to be a different one, and turned the flag on now that the screen's own words are true.

The blob engine: filesystem or S3

Two engines, picked with a toggle: Filesystem (the default — cached bodies live under DATA_DIR/blobs, and backing them up is exactly "copy DATA_DIR", see Operations) or S3-compatible (any endpoint speaking the S3 API — MinIO, Cloudflare R2, Backblaze B2, Wasabi, or AWS S3 itself), configured with an endpoint, bucket, region, access key and secret key, plus an optional path-style toggle for endpoints that need it.

Objects are always streamed through SkimMail, never served from a public bucket URL — even on S3, message content keeps the same sanitization, tracker-blocking and per-request authorization that filesystem storage has, and frequently-read blobs are cached locally for speed regardless of which engine is active. Choosing S3 does not turn your bucket into something a mail client or a browser talks to directly.

Test connection builds the candidate configuration and probes it with one cheap Stat call against a sentinel key — a "not found" response counts as success, since it proves the bucket and credentials are reachable without requiring anything to already exist there. Run this before saving; a misconfigured S3 target is refused at save/switch time by the same probe (see below), but seeing the failure early costs nothing.

Two different buttons, two different levels of care

This is the one distinction worth reading twice before you press either:

  • Save persists the new engine and switches the live blob cache to it immediately. If the new location is genuinely different from the old one (a different S3 bucket, or crossing from filesystem to S3 or back — rotating only an S3 access key does not count as a move), the old engine's cached bodies are left behind, unreferenced, and the index that pointed at them is dropped. Nothing is deleted from the old store — SkimMail will not reach into an S3 bucket that might also be your backup destination and start removing objects — but nothing that used to be cached is copied forward either. This is safe precisely because the body cache is a cache: anything abandoned this way is simply re-fetched from each account's IMAP server the next time it's opened.
  • Switch & migrate does the same switch, then walks every key in the old store and copies it into the new one in the background, skipping keys already present (safe to re-run) and counting copied/skipped/failed as it goes. This is the one to use if you want yesterday's cached bodies to still be a local hit on the new engine instead of a fresh IMAP fetch.

Either way, the previous engine's stored objects are never deleted by this screen. A switch is safe to reconsider: point the configuration back and your old bytes, if you didn't already overwrite that bucket with something else, are still there.

The database section is a runbook, not a button

Moving from SQLite to Postgres or MySQL is presented as a wizard that prints commands for you to run, not an action SkimMail performs on your behalf: pick a target engine, paste a connection string (checked only for shape — a regex, not a real connection attempt), and get back a short script using skimmail config set (or the equivalent environment variables, which win over a config-set value) to point the server at the new database, plus a reminder to sign in again afterward.

No rows are copied. SkimMail's message store is a cache it rebuilds from each account's IMAP server, so "migrating" the database means standing up an empty Postgres or MySQL instance, pointing SkimMail at it, and re-adding your accounts — the sync that follows repopulates everything. Your existing SQLite file under DATA_DIR is left completely untouched, which is what makes the whole thing reversible: point the configuration back at DB_DRIVER=sqlite and you are exactly where you started.

Limits

Available since 1.14.0 (flag turned on); the blob-engine mechanics themselves are 1.11.0
Role owner
Blob engines filesystem, S3-compatible
Database "migration" a runbook (commands to copy), not an automated action
Concurrency one blob backfill at a time; starting a second while one runs is a no-op
S3 availability compiled into every official build since 1.4.3

What it does not do

  • It does not migrate the database for you. The wizard on this screen validates a connection string's shape and hands you commands; it makes no network call and copies no rows. See above.
  • Switching the blob engine with plain Save does not carry old blobs forward. Only Switch & migrate does that; Save alone abandons them in the old store (never deletes them) and forgets the index.
  • It never deletes objects in the store you are leaving. That bucket or directory might be a backup destination too (see Backup and restore); this screen will not guess that it's safe to clear it.
  • A rotated S3 secret key is not treated as a location change. Only the endpoint/bucket/region/path-style identify "the same place" — updating credentials alone triggers neither an abandonment nor a migration.

See also

  • Operations — filesystem backup, and where blobs/ sits under DATA_DIR
  • Message body cache — what is actually stored in a blob, its size/age limits, and at-rest encryption
  • Configuration — the three-plane model, skimmail config, and the boot-only DB_DRIVER/DATABASE_URL/BLOB_STORE/S3_* variables

SkimMail · skimmail@base101.app · 2026-09-15 · commit dffbb18

Clone this wiki locally