2023-09-11 20:23:04 +02:00
|
|
|
{
|
|
|
|
pkgs,
|
|
|
|
lib,
|
|
|
|
config,
|
|
|
|
...
|
|
|
|
}:
|
|
|
|
with lib; let
|
|
|
|
mailman3 = import ./release.nix {};
|
2019-07-01 18:01:23 +02:00
|
|
|
cfg = config.services.mailman3;
|
|
|
|
usePostgresql = cfg.database.type == "postgresql";
|
|
|
|
useSqlite = cfg.database.type == "sqlite3";
|
|
|
|
useMysql = cfg.database.type == "mysql";
|
|
|
|
usePostfix = cfg.mta.type == "postfix";
|
|
|
|
configFile_postfix = pkgs.writeText "postfix.cfg" ''
|
|
|
|
[postfix]
|
|
|
|
transport_file_type: hash
|
|
|
|
postmap_command: ${pkgs.postfix}/bin/postmap
|
|
|
|
'';
|
|
|
|
configFile = pkgs.writeText "mailman.cfg" ''
|
|
|
|
# This File was automatically generated by the mailman3 nixos submodule.
|
|
|
|
# Do not manually edit this file.
|
|
|
|
|
|
|
|
[mailman]
|
|
|
|
site_owner: ${cfg.site_owner}
|
|
|
|
layout: custom
|
|
|
|
|
|
|
|
[paths.custom]
|
|
|
|
archive_dir: ${cfg.paths.archive_dir}
|
|
|
|
bin_dir: ${cfg.paths.bin_dir}
|
|
|
|
cache_dir: ${cfg.paths.cache_dir}
|
|
|
|
data_dir: ${cfg.paths.data_dir}
|
|
|
|
etc_dir: ${cfg.paths.etc_dir}
|
|
|
|
lock_dir: ${cfg.paths.lock_dir}
|
|
|
|
log_dir: ${cfg.paths.log_dir}
|
|
|
|
messages_dir: ${cfg.paths.messages_dir}
|
|
|
|
template_dir: ${cfg.paths.template_dir}
|
|
|
|
var_dir: ${cfg.paths.var_dir}
|
|
|
|
lock_file: ${cfg.paths.lock_file}
|
|
|
|
pid_file: ${cfg.paths.pid_file}
|
|
|
|
|
|
|
|
# The Database Documentation can be found here:
|
|
|
|
# https://mailman.readthedocs.io/en/latest/src/mailman/docs/database.html
|
|
|
|
# https://docs.sqlalchemy.org/en/latest/core/engines.html#database-urls
|
|
|
|
[database]
|
|
|
|
${optionalString useSqlite ''
|
|
|
|
[database]
|
|
|
|
url: sqlite:///${cfg.database.socket}
|
|
|
|
''}
|
|
|
|
${optionalString usePostgresql ''
|
|
|
|
class: mailman.database.postgresql.PostgreSQLDatabase
|
|
|
|
url: postgres://${cfg.database.user}:#dbpass#@${database.host}:${toString cfg.database.port}/${cfg.database.name}
|
|
|
|
''}
|
|
|
|
${optionalString useMysql ''
|
|
|
|
class: mailman.database.mysql.MySQLDatabase
|
|
|
|
url: mysql+pymysql://${cfg.database.user}:#dbpass#@${cfg.database.host}:${toString cfg.database.port}/${cfg.database.name}?charset=utf8&use_unicode=1
|
|
|
|
''}
|
|
|
|
|
|
|
|
[mta]
|
|
|
|
incoming: ${cfg.mta.incoming}
|
|
|
|
outgoing: ${cfg.mta.outgoing}
|
|
|
|
lmtp_host: ${cfg.mta.lmtp_host}
|
|
|
|
lmtp_port: ${toString cfg.mta.lmtp_port}
|
|
|
|
smtp_host: ${cfg.mta.smtp_host}
|
|
|
|
smtp_port: ${toString cfg.mta.smtp_port}
|
|
|
|
smtp_user: ${cfg.mta.smtp_user}
|
|
|
|
smtp_pass: #smtppass#
|
|
|
|
# One of smtp/smtps/starttls, specifies the protocol Mailman will use when
|
|
|
|
# connecting. Typically will correspond to smtp_port: 25 -> smtp, 465 -> smtps,
|
|
|
|
# 587 -> starttls.
|
|
|
|
smtp_secure_mode: smtp
|
|
|
|
configuration: ${configFile_postfix}
|
|
|
|
|
|
|
|
[ARC]
|
|
|
|
enabled: no
|
|
|
|
|
|
|
|
${cfg.extraConfig}
|
|
|
|
'';
|
|
|
|
in {
|
|
|
|
options.services.mailman3 = {
|
|
|
|
enable = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = false;
|
|
|
|
example = true;
|
|
|
|
description = ''
|
|
|
|
Wether to enable mailman3 mailing list management system (core).
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
site_owner = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "changeme@example.com";
|
|
|
|
description = ''
|
|
|
|
mailman3 site owner address.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
user = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "mailman3";
|
|
|
|
description = ''
|
|
|
|
User account under which mailman runs.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
database = {
|
|
|
|
type = mkOption {
|
2023-09-11 20:23:04 +02:00
|
|
|
type = types.enum ["sqlite3" "mysql" "postgres"];
|
2019-07-01 18:01:23 +02:00
|
|
|
default = "sqlite3";
|
|
|
|
example = "mysql";
|
|
|
|
description = ''
|
|
|
|
Database type to use.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
host = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "172.0.0.1";
|
|
|
|
description = ''
|
|
|
|
Database host adress.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
port = mkOption {
|
|
|
|
type = types.nullOr types.int;
|
|
|
|
default = null;
|
|
|
|
description = ''
|
|
|
|
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
name = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "mailman3";
|
|
|
|
description = ''
|
|
|
|
Database name.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
user = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "mailman3";
|
|
|
|
description = ''
|
|
|
|
Database user.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
password = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "";
|
|
|
|
description = ''
|
|
|
|
The password corresponding to <option>database.user</option>.
|
|
|
|
Warning: this is stored in cleartext in the Nix store!
|
|
|
|
Use <option>database.passwordFile</option> instead.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
passwordFile = mkOption {
|
|
|
|
type = types.nullOr types.path;
|
|
|
|
default = null;
|
|
|
|
example = "/run/keys/mailman3-dbpassword";
|
|
|
|
description = ''
|
|
|
|
A file containing the password corresponding to
|
|
|
|
<option>database.user</option>.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
socket = mkOption {
|
|
|
|
type = types.nullOr types.path;
|
|
|
|
default = null;
|
|
|
|
example = "/run/mysqld/mysqld.sock";
|
|
|
|
description = "Path to the unix socket file to use for authentication.";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
paths = {
|
|
|
|
archive_dir = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "${cfg.paths.var_dir}/archives";
|
|
|
|
description = ''
|
|
|
|
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
bin_dir = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "${mailman3.core}/bin";
|
|
|
|
description = ''
|
|
|
|
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
cache_dir = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "${cfg.paths.var_dir}/cache";
|
|
|
|
description = ''
|
|
|
|
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
data_dir = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "${cfg.paths.var_dir}/data";
|
|
|
|
description = ''
|
|
|
|
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
etc_dir = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "${cfg.paths.var_dir}/etc";
|
|
|
|
description = ''
|
|
|
|
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
lock_dir = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "${cfg.paths.var_dir}/locks";
|
|
|
|
description = ''
|
|
|
|
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
log_dir = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "${cfg.paths.var_dir}/logs";
|
|
|
|
description = ''
|
|
|
|
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
messages_dir = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "${cfg.paths.var_dir}/messages";
|
|
|
|
description = ''
|
|
|
|
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
template_dir = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "${cfg.paths.var_dir}/templates";
|
|
|
|
description = ''
|
|
|
|
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
var_dir = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "/var/lib/mailman3";
|
|
|
|
description = ''
|
|
|
|
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
lock_file = mkOption {
|
|
|
|
type = types.path;
|
|
|
|
default = "${cfg.paths.lock_dir}/master.lck";
|
|
|
|
description = ''
|
|
|
|
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
pid_file = mkOption {
|
|
|
|
type = types.path;
|
|
|
|
default = "${cfg.paths.var_dir}/master.pid";
|
|
|
|
description = ''
|
|
|
|
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
mta = {
|
|
|
|
# TODO: add Sentmail and qmail
|
|
|
|
type = mkOption {
|
2023-09-11 20:23:04 +02:00
|
|
|
type = types.enum ["postfix" "exim4"];
|
2019-07-01 18:01:23 +02:00
|
|
|
default = "postfix";
|
|
|
|
example = "exim4";
|
|
|
|
description = ''
|
|
|
|
Database type to use.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
incoming = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "mailman.mta.${cfg.mta.type}.LMTP";
|
|
|
|
description = ''
|
|
|
|
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
outgoing = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "mailman.mta.deliver.deliver";
|
|
|
|
description = ''
|
|
|
|
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
lmtp_host = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "mail.example.com";
|
|
|
|
description = ''
|
|
|
|
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
lmtp_port = mkOption {
|
|
|
|
type = types.int;
|
|
|
|
default = 8024;
|
|
|
|
description = ''
|
|
|
|
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
smtp_host = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "mail.example.com";
|
|
|
|
description = ''
|
|
|
|
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
smtp_port = mkOption {
|
|
|
|
type = types.int;
|
|
|
|
default = 25;
|
|
|
|
description = ''
|
|
|
|
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
smtp_user = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "";
|
|
|
|
description = ''
|
|
|
|
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
smtp_pass = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "";
|
|
|
|
description = ''
|
|
|
|
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
smtp_passFile = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "";
|
|
|
|
description = ''
|
|
|
|
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
extraConfig = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "";
|
|
|
|
example = ''
|
|
|
|
[devmode]
|
|
|
|
enabled: yes
|
|
|
|
recipient: your.address@your.domain
|
|
|
|
'';
|
|
|
|
description = ''
|
|
|
|
Configuration lines appended to the generated mailman3 configuration file.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
config = mkIf cfg.enable {
|
|
|
|
users = mkIf (cfg.user == "mailman3") {
|
|
|
|
users.mailman3 = {
|
|
|
|
description = "Mailman3 Service";
|
|
|
|
home = cfg.paths.var_dir;
|
|
|
|
createHome = true;
|
|
|
|
useDefaultShell = true;
|
2023-09-11 20:23:04 +02:00
|
|
|
packages = [mailman3.core];
|
2019-07-01 18:01:23 +02:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
services.postfix.recipientDelimiter = mkIf usePostfix (mkDefault "+");
|
|
|
|
services.postfix.mapFiles."transport_maps" = mkIf usePostfix (mkDefault "${cfg.paths.data_dir}/postfix_lmtp");
|
|
|
|
services.postfix.mapFiles."local_recipient_maps" = mkIf usePostfix (mkDefault "${cfg.paths.data_dir}/postfix_lmtp");
|
|
|
|
services.postfix.mapFiles."relay_domains" = mkIf usePostfix (mkDefault "${cfg.paths.data_dir}/postfix_domains");
|
|
|
|
|
2023-09-11 20:23:04 +02:00
|
|
|
warnings =
|
|
|
|
optional (cfg.database.password != "")
|
|
|
|
'' config.services.mailman3.database.password will be stored as plaintext
|
|
|
|
in the Nix store. Use database.passwordFile instead.'';
|
2019-07-01 18:01:23 +02:00
|
|
|
|
|
|
|
# Create database passwordFile default when password is configured.
|
2023-09-11 20:23:04 +02:00
|
|
|
services.mailman3.database.passwordFile = mkDefault (toString (pkgs.writeTextFile {
|
|
|
|
name = "mailman3-database-password";
|
|
|
|
text = cfg.database.password;
|
|
|
|
}));
|
2019-07-01 18:01:23 +02:00
|
|
|
|
|
|
|
systemd.services.mailman3 = {
|
|
|
|
description = "GNU Mailing List Manager";
|
2023-09-11 20:23:04 +02:00
|
|
|
after = ["network.target"] ++ lib.optional usePostgresql "postgresql.service" ++ lib.optional useMysql "mysql.service";
|
|
|
|
wantedBy = ["multi-user.target"];
|
2019-07-01 18:01:23 +02:00
|
|
|
|
|
|
|
preStart = let
|
2023-09-11 20:23:04 +02:00
|
|
|
dbpass = fileContents cfg.database.passwordFile;
|
|
|
|
smtppass = fileContents cfg.mta.smtp_passFile;
|
2019-07-01 18:01:23 +02:00
|
|
|
in ''
|
|
|
|
mkdir -p ${cfg.paths.etc_dir}
|
|
|
|
cp ${configFile} ${cfg.paths.etc_dir}/mailman.cfg
|
|
|
|
${optionalString (useMysql || usePostgresql) ''
|
|
|
|
sed -e "s/#dbpass#/${dbpass}/g" -e "s/#smtppass#/${smtppass}/g" -i ${cfg.paths.etc_dir}/mailman.cfg
|
|
|
|
''}
|
|
|
|
chmod 640 ${cfg.paths.etc_dir}/mailman.cfg
|
|
|
|
'';
|
|
|
|
|
|
|
|
serviceConfig = {
|
|
|
|
Type = "forking";
|
|
|
|
User = cfg.user;
|
|
|
|
WorkingDirectory = cfg.paths.var_dir;
|
|
|
|
ExecStart = "${mailman3.core}/bin/mailman start -f";
|
|
|
|
ExecReload = "${mailman3.core}/bin/mailman restart";
|
|
|
|
ExecStop = "${mailman3.core}/bin/mailman stop";
|
|
|
|
};
|
|
|
|
|
|
|
|
environment = {
|
|
|
|
USER = cfg.user;
|
|
|
|
HOME = cfg.paths.var_dir;
|
|
|
|
MAILMAN_CONFIG_FILE = "${cfg.paths.etc_dir}/mailman.cfg";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|