1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 concatMapLines = f: l: lib.concatStringsSep "\n" (map f l);
8
9 cfg = config.services.mlmmj;
10 stateDir = "/var/lib/mlmmj";
11 spoolDir = "/var/spool/mlmmj";
12 listDir = domain: list: "${spoolDir}/${domain}/${list}";
13 listCtl = domain: list: "${listDir domain list}/control";
14 transport = domain: list: "${domain}--${list}@local.list.mlmmj mlmmj:${domain}/${list}";
15 virtual = domain: list: "${list}@${domain} ${domain}--${list}@local.list.mlmmj";
16 alias = domain: list: "${list}: \"|${pkgs.mlmmj}/bin/mlmmj-receive -L ${listDir domain list}/\"";
17 subjectPrefix = list: "[${list}]";
18 listAddress = domain: list: "${list}@${domain}";
19 customHeaders = domain: list: [ "List-Id: ${list}" "Reply-To: ${list}@${domain}" ];
20 footer = domain: list: "To unsubscribe send a mail to ${list}+unsubscribe@${domain}";
21 createList = d: l:
22 let ctlDir = listCtl d l; in
23 ''
24 for DIR in incoming queue queue/discarded archive text subconf unsubconf \
25 bounce control moderation subscribers.d digesters.d requeue \
26 nomailsubs.d
27 do
28 mkdir -p '${listDir d l}'/"$DIR"
29 done
30 ${pkgs.coreutils}/bin/mkdir -p ${ctlDir}
31 echo ${listAddress d l} > '${ctlDir}/listaddress'
32 [ ! -e ${ctlDir}/customheaders ] && \
33 echo "${lib.concatStringsSep "\n" (customHeaders d l)}" > '${ctlDir}/customheaders'
34 [ ! -e ${ctlDir}/footer ] && \
35 echo ${footer d l} > '${ctlDir}/footer'
36 [ ! -e ${ctlDir}/prefix ] && \
37 echo ${subjectPrefix l} > '${ctlDir}/prefix'
38 '';
39in
40
41{
42
43 ###### interface
44
45 options = {
46
47 services.mlmmj = {
48
49 enable = mkOption {
50 type = types.bool;
51 default = false;
52 description = "Enable mlmmj";
53 };
54
55 user = mkOption {
56 type = types.str;
57 default = "mlmmj";
58 description = "mailinglist local user";
59 };
60
61 group = mkOption {
62 type = types.str;
63 default = "mlmmj";
64 description = "mailinglist local group";
65 };
66
67 listDomain = mkOption {
68 type = types.str;
69 default = "localhost";
70 description = "Set the mailing list domain";
71 };
72
73 mailLists = mkOption {
74 type = types.listOf types.str;
75 default = [];
76 description = "The collection of hosted maillists";
77 };
78
79 maintInterval = mkOption {
80 type = types.str;
81 default = "20min";
82 description = ''
83 Time interval between mlmmj-maintd runs, see
84 <citerefentry><refentrytitle>systemd.time</refentrytitle>
85 <manvolnum>7</manvolnum></citerefentry> for format information.
86 '';
87 };
88
89 };
90
91 };
92
93 ###### implementation
94
95 config = mkIf cfg.enable {
96
97 users.users = singleton {
98 name = cfg.user;
99 description = "mlmmj user";
100 home = stateDir;
101 createHome = true;
102 uid = config.ids.uids.mlmmj;
103 group = cfg.group;
104 useDefaultShell = true;
105 };
106
107 users.groups = singleton {
108 name = cfg.group;
109 gid = config.ids.gids.mlmmj;
110 };
111
112 services.postfix = {
113 enable = true;
114 recipientDelimiter= "+";
115 extraMasterConf = ''
116 mlmmj unix - n n - - pipe flags=ORhu user=mlmmj argv=${pkgs.mlmmj}/bin/mlmmj-receive -F -L ${spoolDir}/$nexthop
117 '';
118
119 extraAliases = concatMapLines (alias cfg.listDomain) cfg.mailLists;
120
121 extraConfig = ''
122 transport_maps = hash:${stateDir}/transports
123 virtual_alias_maps = hash:${stateDir}/virtuals
124 propagate_unmatched_extensions = virtual
125 '';
126 };
127
128 environment.systemPackages = [ pkgs.mlmmj ];
129
130 system.activationScripts.mlmmj = ''
131 ${pkgs.coreutils}/bin/mkdir -p ${stateDir} ${spoolDir}/${cfg.listDomain}
132 ${pkgs.coreutils}/bin/chown -R ${cfg.user}:${cfg.group} ${spoolDir}
133 ${concatMapLines (createList cfg.listDomain) cfg.mailLists}
134 echo "${concatMapLines (virtual cfg.listDomain) cfg.mailLists}" > ${stateDir}/virtuals
135 echo "${concatMapLines (transport cfg.listDomain) cfg.mailLists}" > ${stateDir}/transports
136 ${pkgs.postfix}/bin/postmap ${stateDir}/virtuals
137 ${pkgs.postfix}/bin/postmap ${stateDir}/transports
138 '';
139
140 systemd.services."mlmmj-maintd" = {
141 description = "mlmmj maintenance daemon";
142 serviceConfig = {
143 User = cfg.user;
144 Group = cfg.group;
145 ExecStart = "${pkgs.mlmmj}/bin/mlmmj-maintd -F -d ${spoolDir}/${cfg.listDomain}";
146 };
147 };
148
149 systemd.timers."mlmmj-maintd" = {
150 description = "mlmmj maintenance timer";
151 timerConfig.OnUnitActiveSec = cfg.maintInterval;
152 wantedBy = [ "timers.target" ];
153 };
154 };
155
156}