Skip to content

Feature Rules

SkimMail docs edited this page Sep 15, 2026 · 2 revisions

English · Tiếng Việt · 中文

Rules and signals

Since 1.4.0 SkimMail can watch incoming mail and act on it: match on the sender, the subject, a regular expression, which accounts it came from, or a built-in one-time-passcode detector — then route a notification, raise an in-app toast, fire a push, and/or tag the message.

What this solves

A read-first mail reader is something you open when you choose to. That is the point of it, and it is also the problem: the one message that cannot wait — the login code you are staring at a form for — arrives exactly like the other forty. Rules are the narrow exception. They do not sort, file or reply; they tell you that a particular kind of mail just landed, through a channel you are already looking at.

Where it is

Settings ▸ Rules, at operator level or above. Rules are instance-wide, not per-account: a rule with no scope condition applies to every account you own.

When a rule runs

Rules are evaluated on the server, at sync time, against each newly inserted message header. Three consequences follow from that, and all three surprise people:

  • Only new mail is evaluated. A message already in the database is never re-evaluated, so writing a rule does nothing to mail that arrived before it.
  • Only recent mail is evaluated. A message dated more than 48 hours before the sync is treated as backfill, not as an arrival — otherwise a first sync of a year's mail would fire a year's notifications in one burst.
  • Only headers are available. Evaluation happens where the header data already is, before any body is fetched. That is why there is no "has attachment" and no body matching: neither is trustworthy at that point.

If the stored rules cannot be compiled, evaluation is skipped for that sync and logged. A broken rule never fails a sync.

Conditions

A rule carries one or more conditions and a combinator: All conditions or Any condition.

Condition Matches against Notes
Sender contains the From address case-insensitive substring
Subject contains the subject case-insensitive substring
Regex the subject or the snippet Go RE2 — linear time, no catastrophic backtracking
Account / group scope which account the mail arrived on an allowlist of accounts and/or groups
Is OTP the built-in detector no value to type

A pattern is capped at 512 characters. The regular expression is checked when you save, so an invalid one is refused there rather than silently never matching.

Scope is a condition, not a setting. That is worth saying out loud: with Any condition selected, a scope condition makes the rule fire on everything from those accounts, because "any" is satisfied the moment the scope matches. Scope almost always belongs in an All conditions rule.

The OTP detector

Is OTP uses a built-in detector — the same heuristic family iOS AutoFill uses — rather than a pattern you maintain. It scans subject and snippet for a 4–8 digit code (optionally split once, as in 123 456) and counts it only when an OTP keyword sits within 48 characters of it. Keywords are multilingual: English, Vietnamese, Spanish, Portuguese, French, Dutch, German, Japanese, Chinese, Korean, Russian and Turkish forms are all recognised. A bare four-digit year such as 2026 is skipped unless a keyword sits very close to it, because "Rewind 2026" in a subject line was the most common false positive.

The code itself is never stored. Only a boolean flag is persisted on the message. The code rides along into the notification payload and is re-derived at render time for the copy button on the OTP chip in the message list — it is never written to the database, and it never appears in a backup archive.

Detection runs once per message, on first insert only.

Actions

A matched rule can do any combination of four things:

  • Notify these channels — deliver a rule_hit event to the notification channels you pick. Routing is explicit by channel: a rule's channels are not filtered by that channel's Watchtower event toggles. Only the channel's own enabled switch applies. See Notifications.
  • In-app notification (toast) — a toast in any open SkimMail tab, carrying the OTP code with a copy button when there is one.
  • Send push notification — a Web Push / FCM push to your subscribed browsers and devices. This one does go through the ordinary notification gating chain: the master notifications switch, per-account targeting, quiet hours and the content-visibility settings all apply, so a rule cannot push past quiet hours.
  • Set tag — writes a single tag onto the matched message, which you can then filter by from the inbox. One tag per message: if several rules match and more than one sets a tag, the first matching rule in list order wins. Since 1.16.0 a rule with this action also gets a Backfill button on its row — see below. See Tags.

Rules are evaluated in list order and every matching rule fires — this is not a first-match-wins engine. The only first-match rule is the tag.

Applying a rule's tag to mail you already have

Since 1.16.0. A rule's conditions still only ever evaluate live, at sync time, against newly inserted mail — nothing above this line changed. But a rule with a Set tag action now shows a Backfill button on its own row in Settings ▸ Rules, so turning one on does not mean waiting for the matching mail to arrive a second time.

  • Preview costs nothing and changes nothing. Backfill first counts how many stored messages the rule would tag — a genuine dry run, not a button that reports what it just did.
  • It never overwrites a tag that is already there. A message that already carries a tag — from an earlier rule or from your own hand — is counted separately, as already tagged, and left alone.
  • It never sends a notification. Applying a rule to years of stored mail through the normal hit path would mean a matching number of notifications for mail you read long ago; backfill only ever writes the tag column.
  • A disabled rule can be previewed, never applied. Seeing what a rule would cover is how you decide whether to switch it on; Apply refuses until you do, and the preview says so.
  • It costs no network round-trip. Re-evaluation reads the subject, sender address and snippet already stored, re-running the OTP detector against them when the rule needs it — there is no IMAP fetch and no migration behind any of this.

Testing a rule

Test on a rule sends a synthetic rule_hit through that rule's routed channels, synchronously, and reports each channel's HTTP status and round-trip latency. It tests delivery, not matching: it does not check your conditions against any real mail. A rule with no channels has nothing to test — the button says so and the in-app toast still works.

Limits

Available since 1.4.0 (tag action 1.4.1, push action 1.5.0, backfill 1.16.0)
Role operator
Maximum rules 100
Pattern length 512 characters
Tag length 40 characters, counted in characters not bytes
Evaluation window messages dated within 48 hours of the sync
Notification cap 20 hits per account per sync run
Backfill preview samples shown 5 matched messages, by name
  • The notification cap is a flood guard, and it drops silently to you. Once an account's sync run has produced 20 hits, further hits in that run are not notified; the count that was dropped is written to the log. Tags are applied regardless of the cap — the tag action runs before it.
  • Rules are stored as one list, not per-account rows, and are shared by every account on the instance.
  • Disabled rules are still validated when you save, so a disabled rule with a broken regex is refused rather than stored as a trap for later.

What it does not do

  • It does not move, archive, file or delete mail. There is no "move to folder" action and no auto-archive. SkimMail's rules notify and tag; they do not rearrange your mailbox.
  • It does not reply, forward or send anything. SkimMail does not send mail at all.
  • It does not match on the body or on attachments. Only subject, snippet, sender and scope are available at evaluation time.
  • It does not run its notify/toast/push actions on demand. Those still only ever fire live, at sync time, against new mail — there is no "apply rules to existing mail" button for them. Only the tag action can be backfilled onto mail already stored, with the Backfill button above.
  • It does not run per user. Rules are instance-wide.
  • It is not a spam filter. Muting a sender is the tool for that — see Muted and VIP senders.

See also

  • Notifications — the channels a rule routes into, and the push gating chain
  • Tags — what the tag action writes, manual tagging, and the eraser (rename / merge / remove-everywhere)
  • Sync and Sync Health — the sync that rules run inside
  • Security — why the OTP code is never persisted

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

Clone this wiki locally