Skip to content

rules.pkl

Filter rules tag, move, or forward incoming mail during sync. Rules run sequentially — order matters when matches overlap.

Skeleton

rules {
  new { name = "Mailing lists"; match = "header:list-id:"; add_tags { "list" } }
  new {
    name = "Bulk notifications"
    match = "header:precedence:bulk OR header:auto-submitted:auto-generated"
    add_tags { "notification"; "ephemeral" }
    remove_tags { "inbox" }
  }
}

Rule fields

FieldTypeNotes
nameStringShown in --dry-run output
matchStringQuery expression (see below)
add_tagsListing<String>?Tags to add on match
remove_tagsListing<String>?Tags to remove on match
accountsListing<String>?Restrict rule to certain account aliases

Match syntax

The same operators as durian search, with extra header/attachment matchers:

TermMatches
from:valueSender contains substring (case-insensitive)
to:valueAny recipient contains substring
subject:valueSubject contains substring
header:Name:valueAny header matches
header:Name:Header exists (any value)
has:attachmentAt least one attachment
has:attachment:pdfAttachment with that extension/MIME
group:nameExpands to all addresses in the group
AND (implicit)Adjacent terms ANDed
OR / NOT / ( )Explicit operators

Pattern: ephemeral tagging

Mail tagged ephemeral is hidden from the default Inbox and silenced for notifications:

new {
  name = "Newsletters"
  match = "header:list-unsubscribe: NOT header:list-id:"
  add_tags { "newsletter"; "ephemeral" }
  remove_tags { "inbox" }
}

Sidebar inboxes typically use tag:inbox AND NOT tag:ephemeral to surface only “real” mail.

Pattern: GitHub by reason

GitHub sets X-GitHub-Reason on every notification, letting you split by category:

new { name = "GH mentions";  match = "header:x-github-reason:mention";        add_tags { "gh"; "gh/mention" } }
new { name = "GH reviews";   match = "header:x-github-reason:review_requested"; add_tags { "gh"; "gh/review" } }
new { name = "GH CI noise";  match = "header:x-github-reason:ci_activity";    add_tags { "gh"; "ephemeral" }; remove_tags { "inbox" } }

Apply to existing mail

Rules normally run on incoming sync only. To backfill after editing:

durian rules apply --dry-run     # preview
durian rules apply               # commit

Validate

durian validate rules