Skip to content
Tildev0.6.1

Rules for mail

This page shows how to write a rule that sorts the mail that arrives: it marks it read, flags it, moves it to a folder or calls a Lua function. Rules are written in init.lua, in the scripts folder of the root (~/.config/tilde/scripts).

rules.mail("newsletter",
{ from = "news@example.com", header = { ["List-Unsubscribe"] = true } },
{ mark_read = true, move = "Newsletter" })

rules.mail(name, conditions, actions) records a rule. The first argument is its name, the second says which mail it is for, the third says what to do. This rule matches a mail from news@example.com that has a List-Unsubscribe header, marks it read and moves it to the folder Newsletter, which Tilde creates when it is missing.

A rule works on the mail that arrives while Tilde runs, in tt or in tcli watch. To try it on the mail that is already there, see tcli rules. To see it fire, see tcli watch.

Every condition that you give must hold. A text matches when the field contains it, ignoring case. A list of texts matches when any element does.

Key Tests Accepts
from the sender as Name <address>, or the address when there is no name a string or a list
to the To header only; Cc does not count a string or a list
subject the subject a string or a list
header the named headers a table { [name] = text, list or true }; true only needs the header to be there
account the id of the account, ignoring case a string or a list
folder the folder the mail arrived in, exactly (INBOX in any case) a string or a list

The body of a message is never matched. to and header need the headers, so the message is read once, and only when some rule uses them. If it cannot be read, the rules that need the headers do not match.

Key Does
mark_read sets the Seen flag
flag sets the Flagged flag
move moves the mail to a folder of the same account; the folder is created when missing, except INBOX
stop no rule after this one is looked at
run calls a Lua function with the message

A rule needs at least one condition and one action. stop = true alone is an action.

A rule with no folder condition sees only the mail that arrives in INBOX. To sort mail that arrives in another folder, name it:

rules.mail("lists", { folder = "Lists", subject = "[tilde]" }, { flag = true })

A mail that is already in the target folder is not moved.

Rules are looked at in the order they were defined, and every rule that matches contributes:

  • mark_read and flag apply when any matching rule asks for them;
  • move is the one of the first matching rule that has one;
  • a matching rule with stop = true ends the walk after its own actions. A rule that does not match contributes nothing, its stop included.

A rule with the name of an existing one replaces it and keeps its place. Names are unique across mail and chat rules, so a mail rule with the name of a chat rule is refused. rules.off("newsletter") removes a rule and returns true, or false for a name that does not exist. rules.list() returns the names: { mail = { "newsletter" }, chat = { } }.

rules.mail("invoices", { subject = "invoice" }, {
run = function(msg)
log.info("an invoice arrived in {Place}", msg.place)
end,
})

The function gets a table with kind ("mail"), account, id, place (the folder), from, text (the subject), direct, mention and flags (a list of lower case names such as "seen"). place, id and flags are the ones the mail had when it arrived, before the rules moved or marked it.

The function runs after the other steps, in the order of the rules, and the call is queued, so it can run a moment after the mail was moved. A function that fails is a script error and does not stop the next function or the next rule. tcli rules does not call it.

rules.mail refuses a rule that makes no sense and raises an error that names the rule and the key, never the value: an unknown key (the message lists the valid ones), a wrong type, a blank string, an empty list, a rule with no condition or no action. A refused rule is not registered. Run tcli scripts to see the error with its line.

A step that fails is logged and reported, and the next steps still run. The only exception is the move, which does not run when its folder cannot be created.

  • There is no tag action: the mail stores have flags, not keywords.
  • A moved mail can arrive again as a new mail in its target folder. A rule that names that folder sees it, so two rules that move mail back and forth between two folders loop.

Rules for chat are on Rules for chat. All the functions of the rules module are in the Lua API.