1 { config, lib, pkgs, ... }:
4 concatMapLines = f: l: lib.concatStringsSep "\n" (map f l);
6 cfg = config.services.mlmmj;
7 stateDir = "/var/lib/mlmmj";
8 spoolDir = "/var/spool/mlmmj";
9 listDir = domain: list: "${spoolDir}/${domain}/${list}";
10 listCtl = domain: list: "${listDir domain list}/control";
11 transport = domain: list: "${domain}--${list}@local.list.mlmmj mlmmj:${domain}/${list}";
12 virtual = domain: list: "${list}@${domain} ${domain}--${list}@local.list.mlmmj";
13 alias = domain: list: "${list}: \"|${pkgs.mlmmj}/bin/mlmmj-receive -L ${listDir domain list}/\"";
14 subjectPrefix = list: "[${list}]";
15 listAddress = domain: list: "${list}@${domain}";
16 customHeaders = domain: list: [
18 "Reply-To: ${list}@${domain}"
19 "List-Post: <mailto:${list}@${domain}>"
20 "List-Help: <mailto:${list}+help@${domain}>"
21 "List-Subscribe: <mailto:${list}+subscribe@${domain}>"
22 "List-Unsubscribe: <mailto:${list}+unsubscribe@${domain}>"
24 footer = domain: list: "To unsubscribe send a mail to ${list}+unsubscribe@${domain}";
26 let ctlDir = listCtl d l; in
28 for DIR in incoming queue queue/discarded archive text subconf unsubconf \
29 bounce control moderation subscribers.d digesters.d requeue \
32 mkdir -p '${listDir d l}'/"$DIR"
34 ${pkgs.coreutils}/bin/mkdir -p ${ctlDir}
35 echo ${listAddress d l} > '${ctlDir}/listaddress'
36 [ ! -e ${ctlDir}/customheaders ] && \
37 echo "${lib.concatStringsSep "\n" (customHeaders d l)}" > '${ctlDir}/customheaders'
38 [ ! -e ${ctlDir}/footer ] && \
39 echo ${footer d l} > '${ctlDir}/footer'
40 [ ! -e ${ctlDir}/prefix ] && \
41 echo ${subjectPrefix l} > '${ctlDir}/prefix'
53 enable = lib.mkOption {
54 type = lib.types.bool;
56 description = "Enable mlmmj";
62 description = "mailinglist local user";
65 group = lib.mkOption {
68 description = "mailinglist local group";
71 listDomain = lib.mkOption {
73 default = "localhost";
74 description = "Set the mailing list domain";
77 mailLists = lib.mkOption {
78 type = lib.types.listOf lib.types.str;
80 description = "The collection of hosted maillists";
83 maintInterval = lib.mkOption {
87 Time interval between mlmmj-maintd runs, see
88 {manpage}`systemd.time(7)` for format information.
98 config = lib.mkIf cfg.enable {
100 users.users.${cfg.user} = {
101 description = "mlmmj user";
104 uid = config.ids.uids.mlmmj;
106 useDefaultShell = true;
109 users.groups.${cfg.group} = {
110 gid = config.ids.gids.mlmmj;
115 recipientDelimiter= "+";
116 masterConfig.mlmmj = {
126 "argv=${pkgs.mlmmj}/bin/mlmmj-receive"
129 "${spoolDir}/$nexthop"
133 extraAliases = concatMapLines (alias cfg.listDomain) cfg.mailLists;
135 extraConfig = "propagate_unmatched_extensions = virtual";
137 virtual = concatMapLines (virtual cfg.listDomain) cfg.mailLists;
138 transport = concatMapLines (transport cfg.listDomain) cfg.mailLists;
141 environment.systemPackages = [ pkgs.mlmmj ];
143 systemd.tmpfiles.settings."10-mlmmj" = {
145 "${spoolDir}/${cfg.listDomain}".d = { };
147 inherit (cfg) user group;
151 systemd.services.mlmmj-maintd = {
152 description = "mlmmj maintenance daemon";
156 ExecStart = "${pkgs.mlmmj}/bin/mlmmj-maintd -F -d ${spoolDir}/${cfg.listDomain}";
159 ${concatMapLines (createList cfg.listDomain) cfg.mailLists}
160 ${pkgs.postfix}/bin/postmap /etc/postfix/virtual
161 ${pkgs.postfix}/bin/postmap /etc/postfix/transport
165 systemd.timers.mlmmj-maintd = {
166 description = "mlmmj maintenance timer";
167 timerConfig.OnUnitActiveSec = cfg.maintInterval;
168 wantedBy = [ "timers.target" ];