{ pkgs, lib, config, ... }:
with lib;
let
mailman3 = import ./release.nix { };
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 {
type = types.enum [ "sqlite3" "mysql" "postgres" ];
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 .
Warning: this is stored in cleartext in the Nix store!
Use instead.
'';
};
passwordFile = mkOption {
type = types.nullOr types.path;
default = null;
example = "/run/keys/mailman3-dbpassword";
description = ''
A file containing the password corresponding to
.
'';
};
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 {
type = types.enum [ "postfix" "exim4" ];
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;
packages = [ mailman3.core ];
};
};
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");
warnings = optional (cfg.database.password != "")
''config.services.mailman3.database.password will be stored as plaintext
in the Nix store. Use database.passwordFile instead.'';
# Create database passwordFile default when password is configured.
services.mailman3.database.passwordFile =
(mkDefault (toString (pkgs.writeTextFile {
name = "mailman3-database-password";
text = cfg.database.password;
})));
systemd.services.mailman3 = {
description = "GNU Mailing List Manager";
after = [ "network.target" ] ++ lib.optional usePostgresql "postgresql.service" ++ lib.optional useMysql "mysql.service";
wantedBy = [ "multi-user.target" ];
preStart = let
dbpass = (fileContents cfg.database.passwordFile);
smtppass = (fileContents cfg.mta.smtp_passFile);
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";
};
};
};
}