{ config , lib , pkgs , ... }: with lib; let cfg = config.smtprd-ng; smtprd-ng = pkgs.callPackage ./. { }; emails = submodule { options = { email = mkOption { type = types.str; description = '' Email to relay locally received emails to. ''; }; certificate = mkOption { type = types.nullOr types.path; description = '' Path to the public S/MIME certificate for this receiver. Emails will be encrypted with this certificate. ''; }; }; }; in { options.smtprd-ng = { enable = mkEnableOption "smtprd-ng"; package = mkOption { type = types.package; default = smtprd-ng; description = mdDoc '' The smtprd-ng package to use. ''; }; server = { hostname = mkOption { type = types.str; default = "localhost"; description = mdDoc '' The hostname the local SMTP server should listen on. ''; }; port = mkOption { type = types.port; default = 8025; description = mdDoc '' The port the local SMTP server should listen on. ''; }; }; client = { hostname = mkOption { type = types.str; default = ""; description = mdDoc '' The hostname of the remote SMTP server. ''; }; port = mkOption { type = types.port; default = 587; description = mdDoc '' The port of the remote SMTP server. ''; }; username = mkOption { type = types.nullOr types.str; default = null; description = mdDoc '' The username to login to the remote SMTP server. ''; }; password_file = mkOption { type = types.nullOr types.path; default = null; description = mdDoc '' The path to the file containing the password to login to the remote SMTP server. Should not be in /nix/store! ''; }; sender = mkOption { type = types.nullOr types.str; default = null; description = mdDoc '' The email of the sender. Some SMTP servers require this to be the real FROM email address of the user. ''; }; use_tls = mkOption { type = types.bool; default = false; description = mdDoc '' Use TLS to connect. Mutually exclusive with `start_tls` ''; }; start_tls = mkOption { type = types.bool; default = false; description = mdDoc '' Use STARTLS to connect. Mutually exclusive with `use_tls` ''; }; smime_cert = mkOption { type = types.nullOr types.path; default = null; description = mdDoc '' The path to the S/MIME certificate used to sign messages. If empty, will neither encrypt, nor sign relayed messages. ''; }; smime_cert_private = mkOption { type = types.nullOr types.path; default = null; description = mdDoc '' The path to the S/MIME private key for the certificate used to sign messages. Should not be in /nix/store! ''; }; }; emails = mkOption { type = nullOr (listOf emails); default = null; description = '' A required list of recipients. A certificate is optional, but required if messages should be signed and encrypted. ''; example = [ { email = "monitoring.foo@example.com"; certificate = "`/path/to/certificate`"; } { email = "unencrypted@example.com"; certificate = "`null`"; } ]; }; }; config = mkIf cfg.enable { assertions = [ { assertion = cfg.client.use_tls == true && cfg.client.start_tls == true; message = "Use either TLS or STARTTLS, not both."; } { assertion = cfg.client.smime_cert != null && cfg.client.smime_cert_private == null; message = "If a S/MIME certificate should be used to sign messages, the private key to this certificate must be supplied."; } { assertion = cfg.emails != null; message = "At least one recipient must be configured."; } ]; configFile = { text = generators.toINI { } { server = { hostname = cfg.server.hostname; port = cfg.server.port; }; client = { hostname = cfg.client.hostname; port = cfg.client.port; username = cfg.client.username; password_file = cfg.client.password_file; sender = cfg.client.sender; use_tls = cfg.client.use_tls; start_tls = cfg.client.start_tls; smime_cert = cfg.client.smime_cert; smime_cert_private = cfg.client.smime_cert_private; }; emails = cfg.emails; }; systemd.services = { smtprd-ng = { description = "Run local SMTP relay"; wantedBy = [ "multi-user.target" ]; requires = [ "network.target" ]; serviceConfig = { DynamicUser = true; User = "smtprd-ng"; Group = "smtprd-ng"; Restart = "on-failure"; ExecStart = "${cfg.package}/bin/smtprd-ng --config ${configFile}"; }; }; }; }; }; }