11 cfg = config.services.postgrey;
13 natural = with types; addCheck int (x: x >= 0);
14 natural' = with types; addCheck int (x: x > 0);
18 addCheck (either (submodule unixSocket) (submodule inetSocket)) (x: x ? path || x ? port);
20 inetSocket = with types; {
25 example = "127.0.0.1";
26 description = "The address to bind to. Localhost if null";
31 description = "Tcp port to bind to";
36 unixSocket = with types; {
40 default = "/run/postgrey.sock";
41 description = "Path of the unix socket";
47 description = "Mode of the unix socket";
68 [ "services" "postgrey" "socket" ]
72 value = p: getAttrFromPath p config;
84 if value inetAddr == null then
85 { path = "/run/postgrey.sock"; }
88 addr = value inetAddr;
89 port = value inetPort;
96 services.postgrey = with types; {
100 description = "Whether to run the Postgrey daemon";
105 path = "/run/postgrey.sock";
112 description = "Socket to bind to";
114 greylistText = mkOption {
116 default = "Greylisted for %%s seconds";
117 description = "Response status text for greylisted messages; use %%s for seconds left until greylisting is over and %%r for mail domain of recipient";
119 greylistAction = mkOption {
121 default = "DEFER_IF_PERMIT";
122 description = "Response status for greylisted messages (see access(5))";
124 greylistHeader = mkOption {
126 default = "X-Greylist: delayed %%t seconds by postgrey-%%v at %%h; %%d";
127 description = "Prepend header to greylisted mails; use %%t for seconds delayed due to greylisting, %%v for the version of postgrey, %%d for the date, and %%h for the host";
132 description = "Greylist for N seconds";
137 description = "Delete entries from whitelist if they haven't been seen for N days";
139 retryWindow = mkOption {
140 type = either str natural;
143 description = "Allow N days for the first retry. Use string with appended 'h' to specify time in hours";
145 lookupBySubnet = mkOption {
148 description = "Strip the last N bits from IP addresses, determined by IPv4CIDR and IPv6CIDR";
150 IPv4CIDR = mkOption {
153 description = "Strip N bits from IPv4 addresses if lookupBySubnet is true";
155 IPv6CIDR = mkOption {
158 description = "Strip N bits from IPv6 addresses if lookupBySubnet is true";
163 description = "Store data using one-way hash functions (SHA1)";
165 autoWhitelist = mkOption {
166 type = nullOr natural';
168 description = "Whitelist clients after successful delivery of N messages";
170 whitelistClients = mkOption {
173 description = "Client address whitelist files (see postgrey(8))";
175 whitelistRecipients = mkOption {
178 description = "Recipient address whitelist files (see postgrey(8))";
183 config = mkIf cfg.enable {
185 environment.systemPackages = [ pkgs.postgrey ];
190 description = "Postgrey Daemon";
191 uid = config.ids.uids.postgrey;
197 gid = config.ids.gids.postgrey;
202 systemd.services.postgrey =
205 if cfg.socket ? path then
206 "--unix=${cfg.socket.path} --socketmode=${cfg.socket.mode}"
209 optionalString (cfg.socket.addr != null) (cfg.socket.addr + ":")
210 }${toString cfg.socket.port}'';
213 description = "Postfix Greylisting Service";
214 wantedBy = [ "multi-user.target" ];
215 before = [ "postfix.service" ];
217 mkdir -p /var/postgrey
218 chown postgrey:postgrey /var/postgrey
219 chmod 0770 /var/postgrey
224 ${pkgs.postgrey}/bin/postgrey \
226 --group=postgrey --user=postgrey \
227 --dbdir=/var/postgrey \
228 --delay=${toString cfg.delay} \
229 --max-age=${toString cfg.maxAge} \
230 --retry-window=${toString cfg.retryWindow} \
231 ${if cfg.lookupBySubnet then "--lookup-by-subnet" else "--lookup-by-host"} \
232 --ipv4cidr=${toString cfg.IPv4CIDR} --ipv6cidr=${toString cfg.IPv6CIDR} \
233 ${optionalString cfg.privacy "--privacy"} \
234 --auto-whitelist-clients=${
235 toString (if cfg.autoWhitelist == null then 0 else cfg.autoWhitelist)
237 --greylist-action=${cfg.greylistAction} \
238 --greylist-text="${cfg.greylistText}" \
239 --x-greylist-header="${cfg.greylistHeader}" \
240 ${concatMapStringsSep " " (x: "--whitelist-clients=" + x) cfg.whitelistClients} \
241 ${concatMapStringsSep " " (x: "--whitelist-recipients=" + x) cfg.whitelistRecipients}