Rspamd composite symbols
Rspamd composites are used to combine rules and create more complex rules. Composite rules are defined in the composites
section of the configuration.
Configuration
You could use local.d/composites.conf
(which effects changes inside the composites
section) to define new composites or to change/override existing composites. Names of keys here define the name of the composite; the value of the key should be an object that defines the composite's properties & expression, which is a combination of rules.
For example, you can define a composite that fires when two specific symbols are found and replace these symbols weights with its score:
TEST_COMPOSITE {
expression = "SYMBOL1 and SYMBOL2";
score = 5.0;
}
In this case, if a message contains both SYMBOL1
and SYMBOL2
, they will be replaced by the TEST_COMPOSITE
symbol. The weights of SYMBOL1
and SYMBOL2
will be subtracted from the metric accordingly.
Composite expressions
You can use the following operations in a composite expression:
AND
&
- matches true only if both operands are trueOR
|
- matches true if any operands are trueNOT
!
- matches true if operand is false
You can use braces to specify the priority of operations in composite rules. If braces are not used, the operators will be evaluated from left to right. For example:
TEST {
expression = "SYMBOL1 and SYMBOL2 and ( not SYMBOL3 | not SYMBOL4 | not SYMBOL5 )";
score = 10.0;
group = "Some group";
}
Composite rule can include another composites in the body. There is no restriction on the order in which composite rules are defined:
TEST1 {
expression = "SYMBOL1 AND TEST2";
}
TEST2 {
expression = "SYMBOL2 OR NOT SYMBOL3";
}
Composites should not be recursive, but Rspamd usually detects and prevents this automatically.
Note that symbols are removed after composites are applied. Therefore, you cannot rely on one composite to remove a symbol that is used in another composite.
You can also set up policies for composites regarding the symbols that are included in their expression. By default, Rspamd removes the symbols and weights that trigger the composite and replaces them with the symbol and weight of the composite itself. However, you can change this behavior in two ways.
- Set up removal policy for each symbol:
~
: remove symbol only (weight is preserved)-
: do not remove anything (both weight and the symbol itself are preserved)^
: force removing of symbol and weight (by default, Rspamd prefers to leave symbols when some composite wants to remove and another composite wants to leave any of score/name pair)
- Set the default policy for all elements in the expression using
policy
option:default
: default policy - remove weight and symbolremove_weight
: remove weight onlyremove_symbol
: remove symbol onlyleave
: leave both symbol and score
E.g.
TEST_COMPOSITE {
expression = "SYMBOL1 and SYMBOL2";
policy = "leave";
}
TEST_COMPOSITE2 {
expression = "SYMBOL3 and SYMBOL4";
policy = "remove_weight";
}
Composite weight rules
Composites can record symbols in a metric, which can be used to create non-captive composites. For example, you have symbol A
and B
with weights W_a
and W_b
and a composite C
with weight W_c
.
- If
C
isA & B
then if ruleA
and ruleB
matched then these symbols are removed and their weights are removed as well, leading to a single symbolC
with weightW_c
. - If
C
is-A & B
, then ruleA
is preserved, but the symbolC
is inserted. The weight ofA
is preserved as well, so the total weight of-A & B
will beW_a + W_c
(weight ofB
is still removed). - If
C
is~A & B
, then ruleA
is removed, but it's weight is preserved, leading to the total weight ofW_a + W_c
If you have multiple composites that include the same symbol, and one composite wants to remove the symbol while another composite wants to preserve it, the symbol will be preserved by default. Here are some more examples:
COMP1 {
expression = "BLAH | !DATE_IN_PAST";
}
COMP2 {
expression = "!BLAH | DATE_IN_PAST";
}
COMP3 {
expression = "!BLAH | -DATE_IN_PAST";
}
Both BLAH
and DATE_IN_PAST
exist in the message's check results. However, COMP3
wants to preserve DATE_IN_PAST
so it will be saved in the output.
If we rewrite the previous example but replace -
with ~
then DATE_IN_PAST
will be removed (however, its weight won't be removed):
COMP1 {
expression = "BLAH | !DATE_IN_PAST";
}
COMP2 {
expression = "!BLAH | DATE_IN_PAST";
}
COMP3 {
expression = "!BLAH | ~DATE_IN_PAST";
}
When we want to remove a symbol, despite other composites combinations, it is possible to add the prefix ^
to the symbol:
COMP1 {
expression = "BLAH | !DATE_IN_PAST";
}
COMP2 {
expression = "!BLAH | ^DATE_IN_PAST";
}
COMP3 {
expression = "!BLAH | -DATE_IN_PAST";
}
In this example COMP3
wants to save DATE_IN_PAST
once again, however COMP2
overrides this and removes DATE_IN_PAST
.
Composites with symbol groups
It is possible to include a group of symbols in a composite rule. This effectively means any matched symbol of the specified group:
g:<group>
- matches any symbolg+:<group>
- matches any symbol with positive scoreg-:<group>
- matches any symbol with negative score
Removal policies are applied only to the matched symbols and not to the entire group.
TEST2 {
expression = "SYMBOL2 & !g:mua & g+:fuzzy";
}
Disabling composites
You can disable a composite rule by adding enabled = false
to its definition. For example, to disable the DKIM_MIXED
composite defined in the stock configuration, you can add the following to local.d/composites.conf
:
DKIM_MIXED {
enabled = false;
}
You can also disable composites from the users settings from Rspamd 1.9
.
Composites on symbol options
Starting from version 2.0, it is also possible to augment the conditions of composite rules by adding required symbol options. For example, if a symbol SYM
can insert options opt1
and opt2
, you can create a composite expression that only triggers if the opt2
option is presented:
TEST2 {
expression = "SYM[opt2]";
}
[opt2]
syntax means a list of options allowed for a symbol to match. You can also add multiple options:
[opt1,opt2]
- it means that both opt1
and opt2
must be added by a symbol,
or even regular expressions:
[/opt\d/i]
- this must not include comma, even escaped...
or a mix of both:
[/opt\d/i, foo]
In all cases, all matches are required (not just in a single option, but in an options list for a symbol).
In the future, this feature may be extended to support fully functional expressions if needed.