summary refs log tree commit diff
path: root/nixos/modules/services/mail/postfix.nix
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules/services/mail/postfix.nix')
-rw-r--r--nixos/modules/services/mail/postfix.nix233
1 files changed, 152 insertions, 81 deletions
diff --git a/nixos/modules/services/mail/postfix.nix b/nixos/modules/services/mail/postfix.nix
index 3a9e62a0205..6c5d7e92702 100644
--- a/nixos/modules/services/mail/postfix.nix
+++ b/nixos/modules/services/mail/postfix.nix
@@ -9,14 +9,14 @@ let
   group = cfg.group;
   setgidGroup = cfg.setgidGroup;
 
+  haveAliases = cfg.postmasterAlias != "" || cfg.rootAlias != "" || cfg.extraAliases != "";
+  haveTransport = cfg.transport != "";
+  haveVirtual = cfg.virtual != "";
+
   mainCf =
     ''
       compatibility_level = 2
 
-      queue_directory = /var/postfix/queue
-      command_directory = ${pkgs.postfix}/sbin
-      daemon_directory = ${pkgs.postfix}/libexec/postfix
-
       mail_owner = ${user}
       default_privs = nobody
 
@@ -57,8 +57,6 @@ let
         else
           "[" + cfg.relayHost + "]"}
 
-      alias_maps = hash:/var/postfix/conf/aliases
-
       mail_spool_directory = /var/spool/mail/
 
       setgid_group = ${setgidGroup}
@@ -80,7 +78,13 @@ let
     + optionalString (cfg.recipientDelimiter != "") ''
       recipient_delimiter = ${cfg.recipientDelimiter}
     ''
-    + optionalString (cfg.virtual != "") ''
+    + optionalString haveAliases ''
+      alias_maps = hash:/etc/postfix/aliases
+    ''
+    + optionalString haveTransport ''
+      transport_maps = hash:/etc/postfix/transport
+    ''
+    + optionalString haveVirtual ''
       virtual_alias_maps = hash:/etc/postfix/virtual
     ''
     + cfg.extraConfig;
@@ -108,10 +112,14 @@ let
     flush     unix  n       -       n       1000?   0       flush
     proxymap  unix  -       -       n       -       -       proxymap
     proxywrite unix -       -       n       -       1       proxymap
+  ''
+  + optionalString cfg.enableSmtp ''
     smtp      unix  -       -       n       -       -       smtp
     relay     unix  -       -       n       -       -       smtp
     	      -o smtp_fallback_relay=
     #       -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
+  ''
+  + ''
     showq     unix  n       -       n       -       -       showq
     error     unix  -       -       n       -       -       error
     retry     unix  -       -       n       -       -       error
@@ -138,6 +146,7 @@ let
   virtualFile = pkgs.writeText "postfix-virtual" cfg.virtual;
   mainCfFile = pkgs.writeText "postfix-main.cf" mainCf;
   masterCfFile = pkgs.writeText "postfix-master.cf" masterCf;
+  transportFile = pkgs.writeText "postfix-transport" cfg.transport;
 
 in
 
@@ -150,26 +159,36 @@ in
     services.postfix = {
 
       enable = mkOption {
+        type = types.bool;
         default = false;
         description = "Whether to run the Postfix mail server.";
       };
 
+      enableSmtp = mkOption {
+        default = true;
+        description = "Whether to enable smtp in master.cf.";
+      };
+
       setSendmail = mkOption {
+        type = types.bool;
         default = true;
         description = "Whether to set the system sendmail to postfix's.";
       };
 
       user = mkOption {
+        type = types.str;
         default = "postfix";
         description = "What to call the Postfix user (must be used only for postfix).";
       };
 
       group = mkOption {
+        type = types.str;
         default = "postfix";
         description = "What to call the Postfix group (must be used only for postfix).";
       };
 
       setgidGroup = mkOption {
+        type = types.str;
         default = "postdrop";
         description = "
           How to call postfix setgid group (for postdrop). Should
@@ -178,6 +197,7 @@ in
       };
 
       networks = mkOption {
+        type = types.nullOr (types.listOf types.str);
         default = null;
         example = ["192.168.0.1/24"];
         description = "
@@ -188,6 +208,7 @@ in
       };
 
       networksStyle = mkOption {
+        type = types.str;
         default = "";
         description = "
           Name of standard way of trusted network specification to use,
@@ -197,6 +218,7 @@ in
       };
 
       hostname = mkOption {
+        type = types.str;
         default = "";
         description ="
           Hostname to use. Leave blank to use just the hostname of machine.
@@ -205,6 +227,7 @@ in
       };
 
       domain = mkOption {
+        type = types.str;
         default = "";
         description ="
           Domain to use. Leave blank to use hostname minus first component.
@@ -212,6 +235,7 @@ in
       };
 
       origin = mkOption {
+        type = types.str;
         default = "";
         description ="
           Origin to use in outgoing e-mail. Leave blank to use hostname.
@@ -219,6 +243,7 @@ in
       };
 
       destination = mkOption {
+        type = types.nullOr (types.listOf types.str);
         default = null;
         example = ["localhost"];
         description = "
@@ -228,6 +253,7 @@ in
       };
 
       relayDomains = mkOption {
+        type = types.nullOr (types.listOf types.str);
         default = null;
         example = ["localdomain"];
         description = "
@@ -236,6 +262,7 @@ in
       };
 
       relayHost = mkOption {
+        type = types.str;
         default = "";
         description = "
           Mail relay for outbound mail.
@@ -243,6 +270,7 @@ in
       };
 
       lookupMX = mkOption {
+        type = types.bool;
         default = false;
         description = "
           Whether relay specified is just domain whose MX must be used.
@@ -250,11 +278,13 @@ in
       };
 
       postmasterAlias = mkOption {
+        type = types.str;
         default = "root";
         description = "Who should receive postmaster e-mail.";
       };
 
       rootAlias = mkOption {
+        type = types.str;
         default = "";
         description = "
           Who should receive root e-mail. Blank for no redirection.
@@ -262,6 +292,7 @@ in
       };
 
       extraAliases = mkOption {
+        type = types.lines;
         default = "";
         description = "
           Additional entries to put verbatim into aliases file, cf. man-page aliases(8).
@@ -269,6 +300,7 @@ in
       };
 
       extraConfig = mkOption {
+        type = types.lines;
         default = "";
         description = "
           Extra lines to be added verbatim to the main.cf configuration file.
@@ -276,21 +308,25 @@ in
       };
 
       sslCert = mkOption {
+        type = types.str;
         default = "";
         description = "SSL certificate to use.";
       };
 
       sslCACert = mkOption {
+        type = types.str;
         default = "";
         description = "SSL certificate of CA.";
       };
 
       sslKey = mkOption {
+        type = types.str;
         default = "";
         description = "SSL key to use.";
       };
 
       recipientDelimiter = mkOption {
+        type = types.str;
         default = "";
         example = "+";
         description = "
@@ -299,18 +335,39 @@ in
       };
 
       virtual = mkOption {
+        type = types.lines;
         default = "";
         description = "
           Entries for the virtual alias map, cf. man-page virtual(8).
         ";
       };
 
+      transport = mkOption {
+        default = "";
+        description = "
+          Entries for the transport map, cf. man-page transport(8).
+        ";
+      };
+
       extraMasterConf = mkOption {
+        type = types.lines;
         default = "";
         example = "submission inet n - n - - smtpd";
         description = "Extra lines to append to the generated master.cf file.";
       };
 
+      aliasFiles = mkOption {
+        type = types.attrsOf types.path;
+        default = {};
+        description = "Aliases' tables to be compiled and placed into /var/lib/postfix/conf.";
+      };
+
+      mapFiles = mkOption {
+        type = types.attrsOf types.path;
+        default = {};
+        description = "Maps to be compiled and placed into /var/lib/postfix/conf.";
+      };
+
     };
 
   };
@@ -318,90 +375,104 @@ in
 
   ###### implementation
 
-  config = mkIf config.services.postfix.enable {
+  config = mkIf config.services.postfix.enable (mkMerge [
+    {
 
-    environment = {
-      etc = singleton
-        { source = "/var/postfix/conf";
-          target = "postfix";
-        };
-
-      # This makes comfortable for root to run 'postqueue' for example.
-      systemPackages = [ pkgs.postfix ];
-    };
+      environment = {
+        etc = singleton
+          { source = "/var/lib/postfix/conf";
+            target = "postfix";
+          };
 
-    services.mail.sendmailSetuidWrapper = mkIf config.services.postfix.setSendmail {
-      program = "sendmail";
-      source = "${pkgs.postfix}/bin/sendmail";
-      owner = "nobody";
-      group = "postdrop";
-      setuid = false;
-      setgid = true;
-    };
+        # This makes comfortable for root to run 'postqueue' for example.
+        systemPackages = [ pkgs.postfix ];
+      };
 
-    users.extraUsers = singleton
-      { name = user;
-        description = "Postfix mail server user";
-        uid = config.ids.uids.postfix;
-        group = group;
+      services.mail.sendmailSetuidWrapper = mkIf config.services.postfix.setSendmail {
+        program = "sendmail";
+        source = "${pkgs.postfix}/bin/sendmail";
+        group = setgidGroup;
+        setuid = false;
+        setgid = true;
       };
 
-    users.extraGroups =
-      [ { name = group;
+      users.extraUsers = optional (user == "postfix")
+        { name = "postfix";
+          description = "Postfix mail server user";
+          uid = config.ids.uids.postfix;
+          group = group;
+        };
+
+      users.extraGroups =
+        optional (group == "postfix")
+        { name = group;
           gid = config.ids.gids.postfix;
         }
+        ++ optional (setgidGroup == "postdrop")
         { name = setgidGroup;
           gid = config.ids.gids.postdrop;
-        }
-      ];
-
-    systemd.services.postfix =
-      { description = "Postfix mail server";
-
-        wantedBy = [ "multi-user.target" ];
-        after = [ "network.target" ];
-
-        serviceConfig = {
-          Type = "forking";
-          Restart = "always";
-          PIDFile = "/var/postfix/queue/pid/master.pid";
         };
 
-        preStart = ''
-          ${pkgs.coreutils}/bin/mkdir -p /var/spool/mail /var/postfix/conf /var/postfix/queue
-
-          ${pkgs.coreutils}/bin/chown -R ${user}:${group} /var/postfix
-          ${pkgs.coreutils}/bin/chown -R ${user}:${setgidGroup} /var/postfix/queue
-          ${pkgs.coreutils}/bin/chmod -R ug+rwX /var/postfix/queue
-          ${pkgs.coreutils}/bin/chown root:root /var/spool/mail
-          ${pkgs.coreutils}/bin/chmod a+rwxt /var/spool/mail
-          ${pkgs.coreutils}/bin/ln -sf /var/spool/mail /var/
-
-          ln -sf ${pkgs.postfix}/etc/postfix/postfix-files /var/postfix/conf
-
-          ln -sf ${aliasesFile} /var/postfix/conf/aliases
-          ln -sf ${virtualFile} /var/postfix/conf/virtual
-          ln -sf ${mainCfFile} /var/postfix/conf/main.cf
-          ln -sf ${masterCfFile} /var/postfix/conf/master.cf
-
-          ${pkgs.postfix}/sbin/postalias -c /var/postfix/conf /var/postfix/conf/aliases
-          ${pkgs.postfix}/sbin/postmap -c /var/postfix/conf /var/postfix/conf/virtual
-        '';
-
-        script = ''
-          ${pkgs.postfix}/sbin/postfix -c /var/postfix/conf start
-        '';
-
-        reload = ''
-          ${pkgs.postfix}/sbin/postfix -c /var/postfix/conf reload
-        '';
-
-        preStop = ''
-          ${pkgs.postfix}/sbin/postfix -c /var/postfix/conf stop
-        '';
-
-      };
-
-  };
+      systemd.services.postfix =
+        { description = "Postfix mail server";
+
+          wantedBy = [ "multi-user.target" ];
+          after = [ "network.target" ];
+          path = [ pkgs.postfix ];
+
+          serviceConfig = {
+            Type = "forking";
+            Restart = "always";
+            PIDFile = "/var/lib/postfix/queue/pid/master.pid";
+            ExecStart = "${pkgs.postfix}/bin/postfix start";
+            ExecStop = "${pkgs.postfix}/bin/postfix stop";
+            ExecReload = "${pkgs.postfix}/bin/postfix reload";
+          };
+
+          preStart = ''
+            # Backwards compatibility
+            if [ ! -d /var/lib/postfix ] && [ -d /var/postfix ]; then
+              mkdir -p /var/lib
+              mv /var/postfix /var/lib/postfix
+            fi
+            mkdir -p /var/lib/postfix/data /var/lib/postfix/queue/{pid,public,maildrop}
+
+            chown -R ${user}:${group} /var/lib/postfix
+            chown root /var/lib/postfix/queue
+            chown root /var/lib/postfix/queue/pid
+            chgrp -R ${setgidGroup} /var/lib/postfix/queue/{public,maildrop}
+            chmod 770 /var/lib/postfix/queue/{public,maildrop}
+
+            rm -rf /var/lib/postfix/conf
+            mkdir -p /var/lib/postfix/conf
+            ln -sf ${mainCfFile} /var/lib/postfix/conf/main.cf
+            ln -sf ${masterCfFile} /var/lib/postfix/conf/master.cf
+            ${concatStringsSep "\n" (mapAttrsToList (to: from: ''
+              ln -sf ${from} /var/lib/postfix/conf/${to}
+              postalias /var/lib/postfix/conf/${to}
+            '') cfg.aliasFiles)}
+            ${concatStringsSep "\n" (mapAttrsToList (to: from: ''
+              ln -sf ${from} /var/lib/postfix/conf/${to}
+              postmap /var/lib/postfix/conf/${to}
+            '') cfg.mapFiles)}
+
+            mkdir -p /var/spool/mail
+            chown root:root /var/spool/mail
+            chmod a+rwxt /var/spool/mail
+            ln -sf /var/spool/mail /var/
+          '';
+        };
+    }
+
+    (mkIf haveAliases {
+      services.postfix.aliasFiles."aliases" = aliasesFile;
+    })
+    (mkIf haveTransport {
+      services.postfix.mapFiles."transport" = transportFile;
+    })
+    (mkIf haveVirtual {
+      services.postfix.mapFiles."virtual" = virtualFile;
+    })
+  ]);
 
 }