{ nixos-lib, pkgsUnstable, nixpkgs-unstable, vhackPackages, pkgs, extraModules, nixLib, ... }: let domain = "mail.server.test"; scripts = { checkEmailEmpty = pkgs.writeShellScript "assert-empty-emails" '' set -xe # fetchmail returns EXIT_CODE 1 when no new mail fetchmail --nosslcertck --verbose >&2 || [ "$?" -eq 1 ] || { echo "Expected exit code 1." >&2 exit 1 } ''; }; mkUser = user: {nodes, ...}: let domainIp = nodes.server.networking.primaryIPAddress; in { environment.systemPackages = with pkgs; [ fetchmail msmtp procmail ]; users.users."${user}" = {isNormalUser = true;}; systemd.tmpfiles.rules = [ "d /home/${user}/mail 0700 ${user} users - -" "L /home/${user}/.fetchmailrc - - - - /etc/homeSetup/.fetchmailrc" "L /home/${user}/.procmailrc - - - - /etc/homeSetup/.procmailrc" "L /home/${user}/.msmtprc - - - - /etc/homeSetup/.msmtprc" ]; environment.etc = { "homeSetup/.fetchmailrc" = { text = '' poll "${domainIp}" protocol IMAP username "${user}" password "${user}-password" ssl mda procmail; ''; mode = "0600"; inherit user; }; "homeSetup/.procmailrc" = { text = '' DEFAULT=$HOME/mail ''; mode = "0600"; inherit user; }; "homeSetup/.msmtprc" = { text = '' account ${user} host ${domainIp} port 465 from ${user}@${domain} user ${user} password ${user}-password auth on tls on tls_starttls off ''; mode = "0600"; inherit user; }; }; }; in nixos-lib.runTest { hostPkgs = pkgs; # the Nixpkgs package set used outside the VMs name = "email"; node = { specialArgs = {inherit pkgsUnstable vhackPackages nixpkgs-unstable nixLib;}; # Use the nixpkgs as constructed by the `nixpkgs.*` options pkgs = null; }; nodes = { server = {config, ...}: { imports = extraModules ++ [ ../../../../modules ]; vhack = { nginx = { enable = true; selfsign = true; }; stalwart-mail = { enable = true; fqdn = domain; admin = "mailto:admin@${domain}"; security = null; openFirewall = true; principals = [ { class = "individual"; name = "alice"; secret = "alice-password"; email = ["alice@${domain}"]; } { class = "individual"; name = "bob"; secret = "bob-password"; email = ["bob@${domain}"]; } ]; }; }; }; alice = mkUser "alice"; bob = mkUser "bob"; }; testScript = {...}: /* python */ '' start_all() server.wait_for_unit("stalwart-mail.service") server.wait_for_open_port(993) # imap server.wait_for_open_port(465) # smtp with subtest("Both start without mail"): alice.succeed("sudo -u alice ${scripts.checkEmailEmpty}") bob.succeed("sudo -u bob ${scripts.checkEmailEmpty}") with subtest("Alice can send an email to bob"): alice.succeed("sudo -u alice ${pkgs.writeShellScript "alice-send" '' set -xe cat << EOF | msmtp --debug --account alice --tls-certcheck=off bob@${domain} >&2 Hi Bob! This is an email. It contains a subject and a body. ALICE EOF ''}") bob.succeed("sudo -u bob ${pkgs.writeShellScript "bob-receive" '' set -xe fetchmail --nosslcertck --verbose >&2 || { echo New Mail did not arrive exit 1 } ''}") server.copy_from_vm("/var/lib/", "server") bob.copy_from_vm("/home/bob/mail", "bob") ''; }