diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 599ea640f67c..ab7c63117ff3 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -664,6 +664,7 @@ ./services/mail/mailcatcher.nix ./services/mail/mailhog.nix ./services/mail/mailman.nix + ./services/mail/mailpit.nix ./services/mail/mlmmj.nix ./services/mail/nullmailer.nix ./services/mail/offlineimap.nix diff --git a/nixos/modules/services/mail/mailpit.nix b/nixos/modules/services/mail/mailpit.nix new file mode 100644 index 000000000000..c60e30faf0d8 --- /dev/null +++ b/nixos/modules/services/mail/mailpit.nix @@ -0,0 +1,103 @@ +{ + config, + lib, + pkgs, + ... +}: + +let + cfg = config.services.mailpit; + inherit (lib) + cli + concatStringsSep + const + filterAttrs + getExe + mkEnableOption + mkIf + mkOption + types + ; + + isNonNull = v: v != null; + cliFlags = concatStringsSep " " ( + cli.toGNUCommandLine { } (filterAttrs (const isNonNull) cfg.settings) + ); +in +{ + options.services.mailpit = { + enable = mkEnableOption "mailpit"; + + settings = mkOption { + default = { }; + type = types.submodule { + freeformType = types.attrsOf ( + types.oneOf [ + types.str + types.int + types.bool + ] + ); + options = { + database = mkOption { + type = types.nullOr types.str; + default = null; + example = "mailpit.db"; + description = '' + Specify the local database filename to store persistent data. + If `null`, a temporary file will be created that will be removed when the application stops. + It's recommended to specify a relative path. The database will be written into the service's + state directory then. + ''; + }; + max = mkOption { + type = types.ints.unsigned; + default = 500; + description = '' + Maximum number of emails to keep. If the number is exceeded, old emails + will be deleted. + + Set to `0` to never prune old emails. + ''; + }; + listen = mkOption { + default = "0.0.0.0:8025"; + type = types.str; + description = '' + HTTP bind interface and port for UI. + ''; + }; + smtp = mkOption { + default = "0.0.0.0:1025"; + type = types.str; + description = '' + SMTP bind interface and port. + ''; + }; + }; + }; + description = '' + Attribute-set of all flags passed to mailpit. See + [upstream docs](https://mailpit.axllent.org/docs/configuration/runtime-options/) + for all available options. + ''; + }; + }; + + config = mkIf cfg.enable { + systemd.services.mailpit = { + wantedBy = [ "multi-user.target" ]; + after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; + serviceConfig = { + DynamicUser = true; + StateDirectory = "mailpit"; + WorkingDirectory = "%S/mailpit"; + ExecStart = "${getExe pkgs.mailpit} ${cliFlags}"; + Restart = "on-failure"; + }; + }; + }; + + meta.maintainers = lib.teams.flyingcircus.members; +} diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 424ccf4d9a44..fe3336c1e9fb 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -552,6 +552,7 @@ in { magnetico = handleTest ./magnetico.nix {}; mailcatcher = handleTest ./mailcatcher.nix {}; mailhog = handleTest ./mailhog.nix {}; + mailpit = handleTest ./mailpit.nix {}; mailman = handleTest ./mailman.nix {}; man = handleTest ./man.nix {}; mariadb-galera = handleTest ./mysql/mariadb-galera.nix {}; diff --git a/nixos/tests/mailpit.nix b/nixos/tests/mailpit.nix new file mode 100644 index 000000000000..79beb227534b --- /dev/null +++ b/nixos/tests/mailpit.nix @@ -0,0 +1,35 @@ +import ./make-test-python.nix ( + { lib, ... }: + { + name = "mailpit"; + meta.maintainers = lib.teams.flyingcircus.members; + + nodes.machine = + { pkgs, ... }: + { + services.mailpit.enable = true; + + environment.systemPackages = with pkgs; [ swaks ]; + }; + + testScript = '' + start_all() + + from json import loads + + machine.wait_for_unit("mailpit.service") + machine.wait_for_open_port(1025) + machine.wait_for_open_port(8025) + machine.succeed( + 'echo "this is the body of the email" | swaks --to root@example.org --body - --server localhost:1025' + ) + + received = loads(machine.succeed("curl http://localhost:8025/api/v1/messages")) + assert received['total'] == 1 + message = received["messages"][0] + assert len(message['To']) == 1 + assert message['To'][0]['Address'] == 'root@example.org' + assert "this is the body of the email" in message['Snippet'] + ''; + } +) diff --git a/pkgs/servers/mail/mailpit/default.nix b/pkgs/servers/mail/mailpit/default.nix index da62efd9f7a2..fd8f01674d80 100644 --- a/pkgs/servers/mail/mailpit/default.nix +++ b/pkgs/servers/mail/mailpit/default.nix @@ -10,6 +10,7 @@ fetchNpmDeps, testers, mailpit, + nixosTests, }: let @@ -78,9 +79,12 @@ buildGoModule { cp -r ${ui} server/ui/dist ''; - passthru.tests.version = testers.testVersion { - package = mailpit; - command = "mailpit version"; + passthru.tests = { + inherit (nixosTests) mailpit; + version = testers.testVersion { + package = mailpit; + command = "mailpit version"; + }; }; passthru.updateScript = {