1 { config, lib, pkgs, ... }:
7 concatMapLines = f: l: lib.concatStringsSep "\n" (map f l);
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: "-- \nTo unsubscribe send a mail to ${list}+unsubscribe@${domain}";
22 let ctlDir = listCtl d l; in
24 for DIR in incoming queue queue/discarded archive text subconf unsubconf \
25 bounce control moderation subscribers.d digesters.d requeue \
28 mkdir -p '${listDir d l}'/"$DIR"
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'
44 value = lib.mkOption {
49 mailingListConfig = config: {
51 use_template = lib.mkDefault config.useTemplate;
52 recursive = lib.mkDefault config.recursive;
53 process_children_only = lib.mkDefault config.processChildrenOnly;
70 description = "Enable mlmmj";
76 description = "mailinglist local user";
82 description = "mailinglist local group";
85 listDomain = mkOption {
87 default = "localhost";
88 description = "Set the mailing list domain";
91 mailLists = mkOption {
92 type = types.listOf types.str;
94 description = "The collection of hosted maillists";
97 maillists = lib.mkOption {
98 type = types.attrsOf (types.submodule (domain: {
101 (types.submodule (list: {
103 customHeaders = lib.mkOption {
104 type = types.listOf customHeaderOptions;
106 "List-Id: ${list.name}"
107 "Reply-To: ${list.name}@${domain.name}"
109 description = "Custom headers.";
111 footer = lib.mkOption {
113 default = "-- \nTo unsubscribe send a mail to ${list.name}+unsubscribe@${domain.name}";
114 description = "Text to be added as a footer to the mails' body.";
116 lang = lib.mkOption {
117 type = types.enum [ "ast" "cs" "de" "en" "fi" "fr" "gr" "it" "pt" "sk" "zh-cn" ];
119 description = "Language of the templates.";
121 subjectPrefix = lib.mkOption {
123 default = "[${list.name}]";
124 description = "String added as a prefix to the Subject header.";
127 config = mailingListConfig config;
132 description = "Mailing-lists.";
135 maintInterval = mkOption {
139 Time interval between mlmmj-maintd runs, see
140 <citerefentry><refentrytitle>systemd.time</refentrytitle>
141 <manvolnum>7</manvolnum></citerefentry> for format information.
149 description = "Configure postfix to use mlmmj as a transport";
157 ###### implementation
159 config = mkIf cfg.enable {
161 users.users.${cfg.user} = {
162 description = "mlmmj user";
165 uid = config.ids.uids.mlmmj;
167 useDefaultShell = true;
170 users.groups.${cfg.group} = {
171 gid = config.ids.gids.mlmmj;
174 services.postfix = mkIf cfg.postfix.enable {
176 recipientDelimiter = "+";
177 masterConfig.mlmmj = {
186 "user=${cfg.user}:${cfg.group}"
187 "argv=${pkgs.mlmmj}/bin/mlmmj-receive"
190 "${spoolDir}/$nexthop"
194 extraAliases = lib.concatMapStringsSep "\n" (alias cfg.listDomain) cfg.mailLists;
197 propagate_unmatched_extensions = [ "virtual" ];
198 mlmmj_destination_recipient_limit = "1";
201 virtual = lib.concatMapStringsSep "\n" (virtual cfg.listDomain) cfg.mailLists;
202 transport = lib.concatMapStringsSep "\n" (transport cfg.listDomain) cfg.mailLists;
205 environment.systemPackages = [ pkgs.mlmmj ];
207 system.activationScripts.mlmmj = ''
208 ${pkgs.coreutils}/bin/mkdir -p ${stateDir} ${spoolDir}/${cfg.listDomain}
209 ${lib.concatMapStringsSep "\n" (createList cfg.listDomain) cfg.mailLists}
210 ${pkgs.coreutils}/bin/chown -R ${cfg.user}:${cfg.group} ${spoolDir}
213 systemd.services.mlmmj-maintd = {
214 description = "mlmmj maintenance daemon";
218 ExecStart = "${pkgs.mlmmj}/bin/mlmmj-maintd -F -d ${spoolDir}/${cfg.listDomain}";
222 systemd.timers.mlmmj-maintd = {
223 description = "mlmmj maintenance timer";
224 timerConfig.OnUnitActiveSec = cfg.maintInterval;
225 wantedBy = [ "timers.target" ];