Something went wrong. Try again.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226{ config, lib, pkgs, inputs, ...}:let inherit (lib) mkOption mkEnableOption mkPackageOption types ; cfg = config.services.stalwart; configFormat = pkgs.formats.toml { }; configFile = configFormat.generate "stalwart-mail.toml" cfg.settings;
listenerOpts = name: defaultPort: tls: { enable = mkOption { type = types.bool; default = true; };
port = mkOption { type = types.port; default = defaultPort; };
firewallOpen = mkOption { type = types.bool; default = true; };
listenAddress = mkOption { type = types.str; default = "[::]"; };
tls = mkOption { type = types.bool; default = tls; }; };in{ options.services.stalwart = { enable = mkEnableOption "Enables Stalwart service";
package = mkOption { type = types.package; default = pkgs.stalwart; };
dataDir = mkOption { type = types.path; default = "/var/lib/stalwart"; };
settings = mkOption { inherit (configFormat) type; default = { }; description = '' Configuration options for the Stalwart email server. See <https://stalw.art/docs/category/configuration> for available options.
By default, the module is configured to store everything locally. ''; };
hostname = mkOption { type = types.str; };
smtp = listenerOpts "smtp" 25 false;
submissions = listenerOpts "submissions" 465 true; imap = listenerOpts "imap" 993 true; jmap = listenerOpts "jmap" 443 true; sieve = listenerOpts "managesieve" 4190 false; };
config = lib.mkIf cfg.enable { # TODO: open firewall ports
networking.firewall.allowedTCPPorts = lib.lists.flatten [ (lib.lists.optional cfg.smtp.enable cfg.smtp.port) (lib.lists.optional cfg.submissions.enable cfg.submissions.port) (lib.lists.optional cfg.imap.enable cfg.imap.port) (lib.lists.optional cfg.jmap.enable cfg.jmap.port) (lib.lists.optional cfg.sieve.enable cfg.sieve.port) ];
services.stalwart.settings = { tracer.journal = { type = "journal"; level = lib.mkDefault "info"; ansi = false; enable = lib.mkDefault true; };
webadmin = { path = "/var/cache/stalwart"; resource = lib.mkDefault "file://${cfg.package.webadmin}/webadmin.zip"; };
lookup.default.hostname = cfg.hostname;
resolver = { type = lib.mkDefault "system"; public-suffix = lib.mkDefault [ "file://${pkgs.publicsuffix-list}/share/publicsuffix/public_suffix_list.dat" ]; };
server.listener = let mkListener = listCfg: protocol: lib.mkIf listCfg.enable { inherit protocol;
bind = [ "${listCfg.listenAddress}:${toString listCfg.port}" ];
tls.implicit = listCfg.tls; }; in { smtp = mkListener cfg.smtp "smtp"; submissions = mkListener cfg.submissions "smtp"; imap = mkListener cfg.imap "imap"; sieve = mkListener cfg.sieve "managesieve"; jmap = mkListener cfg.jmap "http"; };
store.rocksdb = { type = "rocksdb"; path = lib.mkDefault "${cfg.dataDir}/rocksdb"; purge.frequency = "0 3 *"; };
store.filesystem = { type = "fs"; path = lib.mkDefault "${cfg.dataDir}/store"; purge.frequency = "0 3 *"; };
storage = { data = lib.mkDefault "rocksdb"; fts = lib.mkDefault "rocksdb"; blob = lib.mkDefault "filesystem"; lookup = lib.mkDefault "rocksdb";
# TODO # directory = lib.mkDefault "default"; };
# queue.outbound.tls.starttls = [ # { "if" = "retry_num > 1 && last_error == 'tls'"; "then" = "disable"; } # { "else" = "require"; } # ]; queue.outbound.tls.starttls = "disable"; };
# This service stores a potentially large amount of data. # Running it as a dynamic user would force chown to be run everytime the # service is restarted on a potentially large number of files. # That would cause unnecessary and unwanted delays. users = { groups.stalwart-mail = { }; users.stalwart-mail = { isSystemUser = true; group = "stalwart-mail"; }; };
systemd.services.stalwart = { enable = cfg.enable;
wantedBy = [ "multi-user.target" ]; after = [ "local-fs.target" "network.target" ];
harden = { enable = true; ipSockets = true; onlyLocalhost = false; };
serviceConfig = { ExecStart = "${cfg.package}/bin/stalwart --config=${configFile}";
User = "stalwart-mail"; Group = "stalwart-mail";
# Base from template resources/systemd/stalwart-mail.service Type = "simple"; LimitNOFILE = 65536; KillMode = "process"; KillSignal = "SIGINT"; Restart = "on-failure"; RestartSec = 5; StandardOutput = "journal"; StandardError = "journal"; SyslogIdentifier = "stalwart";
StateDirectory = "stalwart"; CacheDirectory = "stalwart";
# Bind standard privileged ports AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ]; CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
# Hardening PrivateUsers = false; # incompatible with CAP_NET_BIND_SERVICE UMask = "0077"; }; };
# Make admin commands available in the shell environment.systemPackages = [ cfg.package ]; };}