29027fd1e1
Using pkgs.lib on the spine of module evaluation is problematic because the pkgs argument depends on the result of module evaluation. To prevent an infinite recursion, pkgs and some of the modules are evaluated twice, which is inefficient. Using ‘with lib’ prevents this problem.
406 lines
12 KiB
Nix
406 lines
12 KiB
Nix
{ config, lib, pkgs, ... }:
|
|
|
|
with lib;
|
|
|
|
let
|
|
|
|
cfg = config.services.postfix;
|
|
user = cfg.user;
|
|
group = cfg.group;
|
|
setgidGroup = cfg.setgidGroup;
|
|
|
|
mainCf =
|
|
''
|
|
queue_directory = /var/postfix/queue
|
|
command_directory = ${pkgs.postfix}/sbin
|
|
daemon_directory = ${pkgs.postfix}/libexec/postfix
|
|
|
|
mail_owner = ${user}
|
|
default_privs = nobody
|
|
|
|
''
|
|
+ optionalString config.networking.enableIPv6 ''
|
|
inet_protocols = all
|
|
''
|
|
+ (if cfg.networks != null then
|
|
''
|
|
mynetworks = ${concatStringsSep ", " cfg.networks}
|
|
''
|
|
else if cfg.networksStyle != "" then
|
|
''
|
|
mynetworks_style = ${cfg.networksStyle}
|
|
''
|
|
else
|
|
# Postfix default is subnet, but let's play safe
|
|
''
|
|
mynetworks_style = host
|
|
'')
|
|
+ optionalString (cfg.hostname != "") ''
|
|
myhostname = ${cfg.hostname}
|
|
''
|
|
+ optionalString (cfg.domain != "") ''
|
|
mydomain = ${cfg.domain}
|
|
''
|
|
+ optionalString (cfg.origin != "") ''
|
|
myorigin = ${cfg.origin}
|
|
''
|
|
+ optionalString (cfg.destination != null) ''
|
|
mydestination = ${concatStringsSep ", " cfg.destination}
|
|
''
|
|
+ optionalString (cfg.relayDomains != null) ''
|
|
relay_domains = ${concatStringsSep ", " cfg.relayDomains}
|
|
''
|
|
+ ''
|
|
local_recipient_maps =
|
|
|
|
relayhost = ${if cfg.lookupMX || cfg.relayHost == "" then
|
|
cfg.relayHost
|
|
else
|
|
"[" + cfg.relayHost + "]"}
|
|
|
|
alias_maps = hash:/var/postfix/conf/aliases
|
|
|
|
mail_spool_directory = /var/spool/mail/
|
|
|
|
setgid_group = ${setgidGroup}
|
|
''
|
|
+ optionalString (cfg.sslCert != "") ''
|
|
|
|
smtp_tls_CAfile = ${cfg.sslCACert}
|
|
smtp_tls_cert_file = ${cfg.sslCert}
|
|
smtp_tls_key_file = ${cfg.sslKey}
|
|
|
|
smtp_use_tls = yes
|
|
|
|
smtpd_tls_CAfile = ${cfg.sslCACert}
|
|
smtpd_tls_cert_file = ${cfg.sslCert}
|
|
smtpd_tls_key_file = ${cfg.sslKey}
|
|
|
|
smtpd_use_tls = yes
|
|
|
|
recipientDelimiter = ${cfg.recipientDelimiter}
|
|
''
|
|
+ optionalString (cfg.virtual != "") ''
|
|
virtual_alias_maps = hash:/etc/postfix/virtual
|
|
''
|
|
+ cfg.extraConfig;
|
|
|
|
masterCf = ''
|
|
# ==========================================================================
|
|
# service type private unpriv chroot wakeup maxproc command + args
|
|
# (yes) (yes) (yes) (never) (100)
|
|
# ==========================================================================
|
|
smtp inet n - n - - smtpd
|
|
#submission inet n - n - - smtpd
|
|
# -o smtpd_tls_security_level=encrypt
|
|
# -o smtpd_sasl_auth_enable=yes
|
|
# -o smtpd_client_restrictions=permit_sasl_authenticated,reject
|
|
# -o milter_macro_daemon_name=ORIGINATING
|
|
pickup fifo n - n 60 1 pickup
|
|
cleanup unix n - n - 0 cleanup
|
|
qmgr fifo n - n 300 1 qmgr
|
|
tlsmgr unix - - n 1000? 1 tlsmgr
|
|
rewrite unix - - n - - trivial-rewrite
|
|
bounce unix - - n - 0 bounce
|
|
defer unix - - n - 0 bounce
|
|
trace unix - - n - 0 bounce
|
|
verify unix - - n - 1 verify
|
|
flush unix n - n 1000? 0 flush
|
|
proxymap unix - - n - - proxymap
|
|
proxywrite unix - - n - 1 proxymap
|
|
smtp unix - - n - - smtp
|
|
relay unix - - n - - smtp
|
|
-o smtp_fallback_relay=
|
|
# -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
|
|
showq unix n - n - - showq
|
|
error unix - - n - - error
|
|
retry unix - - n - - error
|
|
discard unix - - n - - discard
|
|
local unix - n n - - local
|
|
virtual unix - n n - - virtual
|
|
lmtp unix - - n - - lmtp
|
|
anvil unix - - n - 1 anvil
|
|
scache unix - - n - 1 scache
|
|
${cfg.extraMasterConf}
|
|
'';
|
|
|
|
aliases =
|
|
optionalString (cfg.postmasterAlias != "") ''
|
|
postmaster: ${cfg.postmasterAlias}
|
|
''
|
|
+ optionalString (cfg.rootAlias != "") ''
|
|
root: ${cfg.rootAlias}
|
|
''
|
|
+ cfg.extraAliases
|
|
;
|
|
|
|
aliasesFile = pkgs.writeText "postfix-aliases" aliases;
|
|
virtualFile = pkgs.writeText "postfix-virtual" cfg.virtual;
|
|
mainCfFile = pkgs.writeText "postfix-main.cf" mainCf;
|
|
masterCfFile = pkgs.writeText "postfix-master.cf" masterCf;
|
|
|
|
in
|
|
|
|
{
|
|
|
|
###### interface
|
|
|
|
options = {
|
|
|
|
services.postfix = {
|
|
|
|
enable = mkOption {
|
|
default = false;
|
|
description = "Whether to run the Postfix mail server.";
|
|
};
|
|
|
|
setSendmail = mkOption {
|
|
default = true;
|
|
description = "Whether to set the system sendmail to postfix's.";
|
|
};
|
|
|
|
user = mkOption {
|
|
default = "postfix";
|
|
description = "What to call the Postfix user (must be used only for postfix).";
|
|
};
|
|
|
|
group = mkOption {
|
|
default = "postfix";
|
|
description = "What to call the Postfix group (must be used only for postfix).";
|
|
};
|
|
|
|
setgidGroup = mkOption {
|
|
default = "postdrop";
|
|
description = "
|
|
How to call postfix setgid group (for postdrop). Should
|
|
be uniquely used group.
|
|
";
|
|
};
|
|
|
|
networks = mkOption {
|
|
default = null;
|
|
example = ["192.168.0.1/24"];
|
|
description = "
|
|
Net masks for trusted - allowed to relay mail to third parties -
|
|
hosts. Leave empty to use mynetworks_style configuration or use
|
|
default (localhost-only).
|
|
";
|
|
};
|
|
|
|
networksStyle = mkOption {
|
|
default = "";
|
|
description = "
|
|
Name of standard way of trusted network specification to use,
|
|
leave blank if you specify it explicitly or if you want to use
|
|
default (localhost-only).
|
|
";
|
|
};
|
|
|
|
hostname = mkOption {
|
|
default = "";
|
|
description ="
|
|
Hostname to use. Leave blank to use just the hostname of machine.
|
|
It should be FQDN.
|
|
";
|
|
};
|
|
|
|
domain = mkOption {
|
|
default = "";
|
|
description ="
|
|
Domain to use. Leave blank to use hostname minus first component.
|
|
";
|
|
};
|
|
|
|
origin = mkOption {
|
|
default = "";
|
|
description ="
|
|
Origin to use in outgoing e-mail. Leave blank to use hostname.
|
|
";
|
|
};
|
|
|
|
destination = mkOption {
|
|
default = null;
|
|
example = ["localhost"];
|
|
description = "
|
|
Full (!) list of domains we deliver locally. Leave blank for
|
|
acceptable Postfix default.
|
|
";
|
|
};
|
|
|
|
relayDomains = mkOption {
|
|
default = null;
|
|
example = ["localdomain"];
|
|
description = "
|
|
List of domains we agree to relay to. Default is the same as
|
|
destination.
|
|
";
|
|
};
|
|
|
|
relayHost = mkOption {
|
|
default = "";
|
|
description = "
|
|
Mail relay for outbound mail.
|
|
";
|
|
};
|
|
|
|
lookupMX = mkOption {
|
|
default = false;
|
|
description = "
|
|
Whether relay specified is just domain whose MX must be used.
|
|
";
|
|
};
|
|
|
|
postmasterAlias = mkOption {
|
|
default = "root";
|
|
description = "Who should receive postmaster e-mail.";
|
|
};
|
|
|
|
rootAlias = mkOption {
|
|
default = "";
|
|
description = "
|
|
Who should receive root e-mail. Blank for no redirection.
|
|
";
|
|
};
|
|
|
|
extraAliases = mkOption {
|
|
default = "";
|
|
description = "
|
|
Additional entries to put verbatim into aliases file.
|
|
";
|
|
};
|
|
|
|
extraConfig = mkOption {
|
|
default = "";
|
|
description = "
|
|
Extra lines to be added verbatim to the main.cf configuration file.
|
|
";
|
|
};
|
|
|
|
sslCert = mkOption {
|
|
default = "";
|
|
description = "SSL certificate to use.";
|
|
};
|
|
|
|
sslCACert = mkOption {
|
|
default = "";
|
|
description = "SSL certificate of CA.";
|
|
};
|
|
|
|
sslKey = mkOption {
|
|
default = "";
|
|
description = "SSL key to use.";
|
|
};
|
|
|
|
recipientDelimiter = mkOption {
|
|
default = "";
|
|
example = "+";
|
|
description = "
|
|
Delimiter for address extension: so mail to user+test can be handled by ~user/.forward+test
|
|
";
|
|
};
|
|
|
|
virtual = mkOption {
|
|
default = "";
|
|
description = "
|
|
Entries for the virtual alias map.
|
|
";
|
|
};
|
|
|
|
extraMasterConf = mkOption {
|
|
default = "";
|
|
example = "submission inet n - n - - smtpd";
|
|
description = "Extra lines to append to the generated master.cf file.";
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
###### implementation
|
|
|
|
config = mkIf config.services.postfix.enable {
|
|
|
|
environment = {
|
|
etc = singleton
|
|
{ source = "/var/postfix/conf";
|
|
target = "postfix";
|
|
};
|
|
|
|
# This makes comfortable for root to run 'postqueue' for example.
|
|
systemPackages = [ pkgs.postfix ];
|
|
};
|
|
|
|
services.mail.sendmailSetuidWrapper = mkIf config.services.postfix.setSendmail {
|
|
program = "sendmail";
|
|
source = "${pkgs.postfix}/bin/sendmail";
|
|
owner = "nobody";
|
|
group = "postdrop";
|
|
setuid = false;
|
|
setgid = true;
|
|
};
|
|
|
|
users.extraUsers = singleton
|
|
{ name = user;
|
|
description = "Postfix mail server user";
|
|
uid = config.ids.uids.postfix;
|
|
group = group;
|
|
};
|
|
|
|
users.extraGroups =
|
|
[ { name = group;
|
|
gid = config.ids.gids.postfix;
|
|
}
|
|
{ name = setgidGroup;
|
|
gid = config.ids.gids.postdrop;
|
|
}
|
|
];
|
|
|
|
jobs.postfix =
|
|
# I copy _lots_ of shipped configuration filed
|
|
# that can be left as is. I am afraid the exact
|
|
# will list slightly change in next Postfix
|
|
# release, so listing them all one-by-one in an
|
|
# accurate way is unlikely to be better.
|
|
{ description = "Postfix mail server";
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
after = [ "network.target" ];
|
|
|
|
daemonType = "fork";
|
|
|
|
preStart =
|
|
''
|
|
if ! [ -d /var/spool/postfix ]; then
|
|
${pkgs.coreutils}/bin/mkdir -p /var/spool/mail /var/postfix/conf /var/postfix/queue
|
|
fi
|
|
|
|
${pkgs.coreutils}/bin/chown -R ${user}:${group} /var/postfix
|
|
${pkgs.coreutils}/bin/chown -R ${user}:${setgidGroup} /var/postfix/queue
|
|
${pkgs.coreutils}/bin/chmod -R ug+rwX /var/postfix/queue
|
|
${pkgs.coreutils}/bin/chown root:root /var/spool/mail
|
|
${pkgs.coreutils}/bin/chmod a+rwxt /var/spool/mail
|
|
|
|
ln -sf "${pkgs.postfix}/share/postfix/conf/"* /var/postfix/conf
|
|
|
|
ln -sf ${aliasesFile} /var/postfix/conf/aliases
|
|
ln -sf ${virtualFile} /var/postfix/conf/virtual
|
|
ln -sf ${mainCfFile} /var/postfix/conf/main.cf
|
|
ln -sf ${masterCfFile} /var/postfix/conf/master.cf
|
|
|
|
${pkgs.postfix}/sbin/postalias -c /var/postfix/conf /var/postfix/conf/aliases
|
|
${pkgs.postfix}/sbin/postmap -c /var/postfix/conf /var/postfix/conf/virtual
|
|
|
|
${pkgs.postfix}/sbin/postfix -c /var/postfix/conf start
|
|
'';
|
|
|
|
preStop = ''
|
|
${pkgs.postfix}/sbin/postfix -c /var/postfix/conf stop
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|