1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
Header matching
===============
Mailman can do pattern based header matching during its normal rule
processing. There is a set of site-wide default header matches specified in
the configuration file under the [spam.headers] section.
>>> from mailman.app.lifecycle import create_list
>>> mlist = create_list(u'_xtest@example.com')
Because the default [spam.headers] section is empty, we'll just extend the
current header matching chain with a pattern that matches 4 or more stars,
discarding the message if it hits.
>>> chain = config.chains['header-match']
>>> chain.extend('x-spam-score', '[*]{4,}', 'discard')
First, if the message has no X-Spam-Score header, the message passes through
the chain untouched (i.e. no disposition).
>>> msg = message_from_string("""\
... From: aperson@example.com
... To: _xtest@example.com
... Subject: Not spam
... Message-ID: <one>
...
... This is a message.
... """)
>>> from mailman.core.chains import process
Pass through is seen as nothing being in the log file after processing.
# XXX This checks the vette log file because there is no other evidence
# that this chain has done anything.
>>> import os
>>> fp = open(os.path.join(config.LOG_DIR, 'vette'))
>>> fp.seek(0, 2)
>>> file_pos = fp.tell()
>>> process(mlist, msg, {}, 'header-match')
>>> fp.seek(file_pos)
>>> print 'LOG:', fp.read()
LOG:
<BLANKLINE>
Now, if the header exists but does not match, then it also passes through
untouched.
>>> msg['X-Spam-Score'] = '***'
>>> del msg['subject']
>>> msg['Subject'] = 'This is almost spam'
>>> del msg['message-id']
>>> msg['Message-ID'] = '<two>'
>>> file_pos = fp.tell()
>>> process(mlist, msg, {}, 'header-match')
>>> fp.seek(file_pos)
>>> print 'LOG:', fp.read()
LOG:
<BLANKLINE>
But now if the header matches, then the message gets discarded.
>>> del msg['x-spam-score']
>>> msg['X-Spam-Score'] = '****'
>>> del msg['subject']
>>> msg['Subject'] = 'This is spam, but barely'
>>> del msg['message-id']
>>> msg['Message-ID'] = '<three>'
>>> file_pos = fp.tell()
>>> process(mlist, msg, {}, 'header-match')
>>> fp.seek(file_pos)
>>> print 'LOG:', fp.read()
LOG: ... DISCARD: <three>
<BLANKLINE>
For kicks, let's show a message that's really spammy.
>>> del msg['x-spam-score']
>>> msg['X-Spam-Score'] = '**********'
>>> del msg['subject']
>>> msg['Subject'] = 'This is really spammy'
>>> del msg['message-id']
>>> msg['Message-ID'] = '<four>'
>>> file_pos = fp.tell()
>>> process(mlist, msg, {}, 'header-match')
>>> fp.seek(file_pos)
>>> print 'LOG:', fp.read()
LOG: ... DISCARD: <four>
<BLANKLINE>
Flush out the extended header matching rules.
>>> chain.flush()
List-specific header matching
-----------------------------
Each mailing list can also be configured with a set of header matching regular
expression rules. These are used to impose list-specific header filtering
with the same semantics as the global [spam.headers] section.
The list administrator wants to match not on four stars, but on three plus
signs, but only for the current mailing list.
>>> mlist.header_matches = [('x-spam-score', '[+]{3,}', 'discard')]
A message with a spam score of two pluses does not match.
>>> del msg['x-spam-score']
>>> msg['X-Spam-Score'] = '++'
>>> del msg['message-id']
>>> msg['Message-ID'] = '<five>'
>>> file_pos = fp.tell()
>>> process(mlist, msg, {}, 'header-match')
>>> fp.seek(file_pos)
>>> print 'LOG:', fp.read()
LOG:
A message with a spam score of three pluses does match.
>>> del msg['x-spam-score']
>>> msg['X-Spam-Score'] = '+++'
>>> del msg['message-id']
>>> msg['Message-ID'] = '<six>'
>>> file_pos = fp.tell()
>>> process(mlist, msg, {}, 'header-match')
>>> fp.seek(file_pos)
>>> print 'LOG:', fp.read()
LOG: ... DISCARD: <six>
<BLANKLINE>
As does a message with a spam score of four pluses.
>>> del msg['x-spam-score']
>>> msg['X-Spam-Score'] = '+++'
>>> del msg['message-id']
>>> msg['Message-ID'] = '<seven>'
>>> file_pos = fp.tell()
>>> process(mlist, msg, {}, 'header-match')
>>> fp.seek(file_pos)
>>> print 'LOG:', fp.read()
LOG: ... DISCARD: <seven>
<BLANKLINE>
|