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