Customer-suggested feature (spam triage use case, see support thread 2026-09-09). Request is for a Sieve test condition that checks whether a message's From address matches a saved CardDAV contact for that mailbox, so scripts can tag (not block) mail from non-contacts, e.g. addheader "X-Not-A-Contact" "true", for later review. Explicitly not looking for auto allow/deny, since plenty of legitimate mail (banks, government, retailers) will never be a personal contact.
Confirmed nothing like this exists today: grep -n "contacts" helpers/sieve/*.js -i returns zero matches across engine.js, extensions.js, filter-handler.js, integration.js, validator.js, security.js, managesieve-server.js, parser-generated.js, store.js, script-checker.js. No :contacts match-type, no contact test anywhere in the registered test inventory (engine.js, evaluateTest switch, lines ~637-739).
Feasibility: this is a scoped addition, not a rebuild or third-party fork. The Sieve engine is fully in-house (custom PEG grammar in helpers/sieve/grammar.pegjs, compiled to parser-generated.js, executed by a switch-dispatch interpreter in engine.js), so no vendored Sieve library constraint applies. Contacts are already stored per-alias (app/models/contacts.js, emails[].value field, isolated per-alias via the per-alias SQLite database in helpers/get-database.js), and the alias identity needed to query that alias's contacts is already threaded into the engine's execution context today (filter-handler.js processMessage(aliasId, message, context), populated from session.user.alias_id in helpers/parse-payload.js). The engine also already supports async test evaluation (see DuplicateTest, engine.js:713), so an async contacts lookup fits the existing pattern.
Scope of work: grammar change in grammar.pegjs (+ regenerate parser-generated.js) for a new test/match-type, a new case in engine.js's evaluateTest switch that queries Contacts by the alias's address book and matches against the From header, and updating the supported-capabilities lists (helpers/sieve/index.js, engine.js, filter-handler.js, managesieve-server.js, script-checker.js, validator.js, extensions.js) if exposed as a named extension/capability.
Customer-suggested feature (spam triage use case, see support thread 2026-09-09). Request is for a Sieve test condition that checks whether a message's From address matches a saved CardDAV contact for that mailbox, so scripts can tag (not block) mail from non-contacts, e.g. addheader "X-Not-A-Contact" "true", for later review. Explicitly not looking for auto allow/deny, since plenty of legitimate mail (banks, government, retailers) will never be a personal contact.
Confirmed nothing like this exists today: grep -n "contacts" helpers/sieve/*.js -i returns zero matches across engine.js, extensions.js, filter-handler.js, integration.js, validator.js, security.js, managesieve-server.js, parser-generated.js, store.js, script-checker.js. No :contacts match-type, no contact test anywhere in the registered test inventory (engine.js, evaluateTest switch, lines ~637-739).
Feasibility: this is a scoped addition, not a rebuild or third-party fork. The Sieve engine is fully in-house (custom PEG grammar in helpers/sieve/grammar.pegjs, compiled to parser-generated.js, executed by a switch-dispatch interpreter in engine.js), so no vendored Sieve library constraint applies. Contacts are already stored per-alias (app/models/contacts.js, emails[].value field, isolated per-alias via the per-alias SQLite database in helpers/get-database.js), and the alias identity needed to query that alias's contacts is already threaded into the engine's execution context today (filter-handler.js processMessage(aliasId, message, context), populated from session.user.alias_id in helpers/parse-payload.js). The engine also already supports async test evaluation (see DuplicateTest, engine.js:713), so an async contacts lookup fits the existing pattern.
Scope of work: grammar change in grammar.pegjs (+ regenerate parser-generated.js) for a new test/match-type, a new case in engine.js's evaluateTest switch that queries Contacts by the alias's address book and matches against the From header, and updating the supported-capabilities lists (helpers/sieve/index.js, engine.js, filter-handler.js, managesieve-server.js, script-checker.js, validator.js, extensions.js) if exposed as a named extension/capability.