1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7let
8 cfg = config.services.spamassassin;
9 spamassassin-local-cf = pkgs.writeText "local.cf" cfg.config;
10
11in
12
13{
14 options = {
15
16 services.spamassassin = {
17 enable = lib.mkEnableOption "the SpamAssassin daemon";
18
19 debug = lib.mkOption {
20 type = lib.types.bool;
21 default = false;
22 description = "Whether to run the SpamAssassin daemon in debug mode";
23 };
24
25 config = lib.mkOption {
26 type = lib.types.lines;
27 description = ''
28 The SpamAssassin local.cf config
29
30 If you are using this configuration:
31
32 add_header all Status _YESNO_, score=_SCORE_ required=_REQD_ tests=_TESTS_ autolearn=_AUTOLEARN_ version=_VERSION_
33
34 Then you can Use this sieve filter:
35
36 require ["fileinto", "reject", "envelope"];
37
38 if header :contains "X-Spam-Flag" "YES" {
39 fileinto "spam";
40 }
41
42 Or this procmail filter:
43
44 :0:
45 * ^X-Spam-Flag: YES
46 /var/vpopmail/domains/lastlog.de/js/.maildir/.spam/new
47
48 To filter your messages based on the additional mail headers added by spamassassin.
49 '';
50 example = ''
51 #rewrite_header Subject [***** SPAM _SCORE_ *****]
52 required_score 5.0
53 use_bayes 1
54 bayes_auto_learn 1
55 add_header all Status _YESNO_, score=_SCORE_ required=_REQD_ tests=_TESTS_ autolearn=_AUTOLEARN_ version=_VERSION_
56 '';
57 default = "";
58 };
59
60 initPreConf = lib.mkOption {
61 type = with lib.types; either str path;
62 description = "The SpamAssassin init.pre config.";
63 apply = val: if builtins.isPath val then val else pkgs.writeText "init.pre" val;
64 default = ''
65 #
66 # to update this list, run this command in the rules directory:
67 # grep 'loadplugin.*Mail::SpamAssassin::Plugin::.*' -o -h * | sort | uniq
68 #
69
70 #loadplugin Mail::SpamAssassin::Plugin::AccessDB
71 #loadplugin Mail::SpamAssassin::Plugin::AntiVirus
72 loadplugin Mail::SpamAssassin::Plugin::AskDNS
73 # loadplugin Mail::SpamAssassin::Plugin::ASN
74 loadplugin Mail::SpamAssassin::Plugin::AutoLearnThreshold
75 #loadplugin Mail::SpamAssassin::Plugin::AWL
76 loadplugin Mail::SpamAssassin::Plugin::Bayes
77 loadplugin Mail::SpamAssassin::Plugin::BodyEval
78 loadplugin Mail::SpamAssassin::Plugin::Check
79 #loadplugin Mail::SpamAssassin::Plugin::DCC
80 loadplugin Mail::SpamAssassin::Plugin::DKIM
81 loadplugin Mail::SpamAssassin::Plugin::DMARC
82 loadplugin Mail::SpamAssassin::Plugin::DNSEval
83 loadplugin Mail::SpamAssassin::Plugin::FreeMail
84 loadplugin Mail::SpamAssassin::Plugin::HeaderEval
85 loadplugin Mail::SpamAssassin::Plugin::HTMLEval
86 loadplugin Mail::SpamAssassin::Plugin::HTTPSMismatch
87 loadplugin Mail::SpamAssassin::Plugin::ImageInfo
88 loadplugin Mail::SpamAssassin::Plugin::MIMEEval
89 loadplugin Mail::SpamAssassin::Plugin::MIMEHeader
90 # loadplugin Mail::SpamAssassin::Plugin::PDFInfo
91 #loadplugin Mail::SpamAssassin::Plugin::PhishTag
92 loadplugin Mail::SpamAssassin::Plugin::Pyzor
93 loadplugin Mail::SpamAssassin::Plugin::Razor2
94 # loadplugin Mail::SpamAssassin::Plugin::RelayCountry
95 loadplugin Mail::SpamAssassin::Plugin::RelayEval
96 loadplugin Mail::SpamAssassin::Plugin::ReplaceTags
97 # loadplugin Mail::SpamAssassin::Plugin::Rule2XSBody
98 # loadplugin Mail::SpamAssassin::Plugin::Shortcircuit
99 loadplugin Mail::SpamAssassin::Plugin::SpamCop
100 loadplugin Mail::SpamAssassin::Plugin::SPF
101 loadplugin Mail::SpamAssassin::Plugin::TextCat
102 # loadplugin Mail::SpamAssassin::Plugin::TxRep
103 loadplugin Mail::SpamAssassin::Plugin::URIDetail
104 loadplugin Mail::SpamAssassin::Plugin::URIDNSBL
105 loadplugin Mail::SpamAssassin::Plugin::URIEval
106 # loadplugin Mail::SpamAssassin::Plugin::URILocalBL
107 loadplugin Mail::SpamAssassin::Plugin::VBounce
108 loadplugin Mail::SpamAssassin::Plugin::WhiteListSubject
109 loadplugin Mail::SpamAssassin::Plugin::WLBLEval
110 '';
111 };
112 };
113 };
114
115 config = lib.mkIf cfg.enable {
116 environment.etc."mail/spamassassin/init.pre".source = cfg.initPreConf;
117 environment.etc."mail/spamassassin/local.cf".source = spamassassin-local-cf;
118
119 # Allow users to run 'spamc'.
120 environment.systemPackages = [ pkgs.spamassassin ];
121
122 users.users.spamd = {
123 description = "Spam Assassin Daemon";
124 home = "/var/lib/spamassassin";
125 uid = config.ids.uids.spamd;
126 group = "spamd";
127 };
128
129 users.groups.spamd = {
130 gid = config.ids.gids.spamd;
131 };
132
133 systemd.services.sa-update = {
134 # Needs to be able to contact the update server.
135 wants = [ "network-online.target" ];
136 after = [ "network-online.target" ];
137
138 serviceConfig = {
139 Type = "oneshot";
140 User = "spamd";
141 Group = "spamd";
142 StateDirectory = "spamassassin";
143 ExecStartPost = "+${config.systemd.package}/bin/systemctl -q --no-block try-reload-or-restart spamd.service";
144 };
145
146 script = ''
147 set +e
148 ${pkgs.spamassassin}/bin/sa-update --verbose --gpghomedir=/var/lib/spamassassin/sa-update-keys/
149 rc=$?
150 set -e
151
152 if [[ $rc -gt 1 ]]; then
153 # sa-update failed.
154 exit $rc
155 fi
156
157 if [[ $rc -eq 1 ]]; then
158 # No update was available, exit successfully.
159 exit 0
160 fi
161
162 # An update was available and installed. Compile the rules.
163 ${pkgs.spamassassin}/bin/sa-compile
164 '';
165 };
166
167 systemd.timers.sa-update = {
168 description = "sa-update-service";
169 partOf = [ "sa-update.service" ];
170 wantedBy = [ "timers.target" ];
171 timerConfig = {
172 OnCalendar = "1:*";
173 Persistent = true;
174 };
175 };
176
177 systemd.services.spamd = {
178 description = "SpamAssassin Server";
179
180 wantedBy = [ "multi-user.target" ];
181 wants = [ "sa-update.service" ];
182 after = [
183 "network.target"
184 "sa-update.service"
185 ];
186
187 reloadTriggers = [
188 config.environment.etc."mail/spamassassin/init.pre".source
189 config.environment.etc."mail/spamassassin/local.cf".source
190 ];
191
192 serviceConfig = {
193 User = "spamd";
194 Group = "spamd";
195 ExecStart = "+${pkgs.spamassassin}/bin/spamd ${lib.optionalString cfg.debug "-D"} --username=spamd --groupname=spamd --virtual-config-dir=%S/spamassassin/user-%u --allow-tell --pidfile=/run/spamd.pid";
196 ExecReload = "+${pkgs.coreutils}/bin/kill -HUP $MAINPID";
197 StateDirectory = "spamassassin";
198 };
199 };
200 };
201}