{ lib, pkgs, config, name, nodes, ... }:
let
getDomains = p: lib.mapAttrsToList (n: v: v.fqdn) (lib.filterAttrs (n: v: v.receive) p.emailPolicies);
bydomain = builtins.mapAttrs (n: getDomains) nodes.eldiron.config.myServices.dns.zones;
receiving_domains = lib.flatten (builtins.attrValues bydomain);
in
{
options.myServices.mailBackup.enable = lib.mkEnableOption "enable MX backup services";
config = lib.mkIf config.myServices.mailBackup.enable {
myServices.mail.milters.enable = true;
security.acme.certs."mail" = {
postRun = ''
systemctl restart postfix.service
'';
domain = config.hostEnv.fqdn;
extraDomainNames = let
zonesWithMx = builtins.attrNames (lib.filterAttrs (n: v: v.hasEmail) nodes.eldiron.config.myServices.dns.zones);
mxs = map (n: "${config.myEnv.servers."${name}".mx.subdomain}.${n}") zonesWithMx;
in mxs;
};
secrets.keys = {
"postfix/mysql_alias_maps" = {
user = config.services.postfix.user;
group = config.services.postfix.group;
permissions = "0440";
text = ''
# We need to specify that option to trigger ssl connection
tls_ciphers = TLSv1.2
user = ${config.myEnv.mail.postfix.mysql.user}
password = ${config.myEnv.mail.postfix.mysql.password}
hosts = ${config.myEnv.mail.postfix.mysql.remoteHost}
dbname = ${config.myEnv.mail.postfix.mysql.database}
query = SELECT DISTINCT 1
FROM forwardings
WHERE
((regex = 1 AND '%s' REGEXP CONCAT('^',source,'$') ) OR (regex = 0 AND source = '%s'))
AND active = 1
AND '%s' NOT IN
(
SELECT source
FROM forwardings_blacklisted
WHERE source = '%s'
) UNION
SELECT 'devnull@immae.eu'
FROM forwardings_blacklisted
WHERE source = '%s'
'';
};
"postfix/ldap_mailboxes" = {
user = config.services.postfix.user;
group = config.services.postfix.group;
permissions = "0440";
text = ''
server_host = ldaps://${config.myEnv.mail.dovecot.ldap.host}:636
search_base = ${config.myEnv.mail.dovecot.ldap.base}
query_filter = ${config.myEnv.mail.dovecot.ldap.postfix_mailbox_filter}
bind_dn = ${config.myEnv.mail.dovecot.ldap.dn}
bind_pw = ${config.myEnv.mail.dovecot.ldap.password}
result_attribute = immaePostfixAddress
result_format = dummy
version = 3
'';
};
"postfix/sympa_mailbox_maps" = {
user = config.services.postfix.user;
group = config.services.postfix.group;
permissions = "0440";
text = ''
hosts = ${config.myEnv.mail.sympa.postgresql.host}
user = ${config.myEnv.mail.sympa.postgresql.user}
password = ${config.myEnv.mail.sympa.postgresql.password}
dbname = ${config.myEnv.mail.sympa.postgresql.database}
query = SELECT DISTINCT 1 FROM list_table WHERE '%s' IN (
CONCAT(name_list, '@', robot_list),
CONCAT(name_list, '-request@', robot_list),
CONCAT(name_list, '-editor@', robot_list),
CONCAT(name_list, '-unsubscribe@', robot_list),
CONCAT(name_list, '-owner@', robot_list),
CONCAT('sympa-request@', robot_list),
CONCAT('sympa-owner@', robot_list),
CONCAT('sympa@', robot_list),
CONCAT('listmaster@', robot_list),
CONCAT('bounce@', robot_list),
CONCAT('abuse-feedback-report@', robot_list)
)
'';
};
"postfix/ldap_ejabberd_users_immae_fr" = {
user = config.services.postfix.user;
group = config.services.postfix.group;
permissions = "0440";
text = ''
server_host = ldaps://${config.myEnv.jabber.ldap.host}:636
search_base = ${config.myEnv.jabber.ldap.base}
query_filter = ${config.myEnv.jabber.postfix_user_filter}
domain = immae.fr
bind_dn = ${config.myEnv.jabber.ldap.dn}
bind_pw = ${config.myEnv.jabber.ldap.password}
result_attribute = immaeXmppUid
result_format = ejabberd@localhost
version = 3
'';
};
};
networking.firewall.allowedTCPPorts = [ 25 ];
users.users."${config.services.postfix.user}".extraGroups = [ "keys" ];
services.filesWatcher.postfix = {
restart = true;
paths = [
config.secrets.fullPaths."postfix/mysql_alias_maps"
config.secrets.fullPaths."postfix/sympa_mailbox_maps"
config.secrets.fullPaths."postfix/ldap_ejabberd_users_immae_fr"
config.secrets.fullPaths."postfix/ldap_mailboxes"
];
};
services.postfix = {
mapFiles = let
virtual_map = {
virtual = let
cfg = config.myEnv.monitoring.email_check.eldiron;
address = "${cfg.mail_address}@${cfg.mail_domain}";
aliases = config.myEnv.mail.postfix.common_aliases;
in pkgs.writeText "postfix-virtual" (
builtins.concatStringsSep "\n" (
[ "${address} 1"
] ++
map (a: "${a} 1") config.myEnv.mail.postfix.other_aliases ++
lib.lists.flatten (map (domain: map (alias: "${alias}@${domain} 1") aliases) receiving_domains)
)
);
};
in
virtual_map;
config = {
### postfix module overrides
readme_directory = "${pkgs.postfix}/share/postfix/doc";
smtp_tls_CAfile = lib.mkForce "";
smtp_tls_cert_file = lib.mkForce "";
smtp_tls_key_file = lib.mkForce "";
message_size_limit = "1073741824"; # Don't put 0 here, it's not equivalent to "unlimited"
mailbox_size_limit = "1073741825"; # Workaround, local delivered mails should all go through scripts
alias_database = "\$alias_maps";
### Relay domains
relay_domains = receiving_domains;
relay_recipient_maps = let
virtual_alias_maps = [
"hash:/etc/postfix/virtual"
"mysql:${config.secrets.fullPaths."postfix/mysql_alias_maps"}"
"ldap:${config.secrets.fullPaths."postfix/ldap_ejabberd_users_immae_fr"}"
];
virtual_mailbox_maps = [
"ldap:${config.secrets.fullPaths."postfix/ldap_mailboxes"}"
"pgsql:${config.secrets.fullPaths."postfix/sympa_mailbox_maps"}"
];
in
virtual_alias_maps ++ virtual_mailbox_maps;
smtpd_relay_restrictions = [
"defer_unauth_destination"
];
### Additional smtpd configuration
smtpd_tls_received_header = "yes";
smtpd_tls_loglevel = "1";
### Email sending configuration
smtp_tls_security_level = "may";
smtp_tls_loglevel = "1";
### Force ip bind for smtp
smtp_bind_address = builtins.head config.myEnv.servers."${name}".ips.main.ip4;
smtp_bind_address6 = builtins.head config.myEnv.servers."${name}".ips.main.ip6;
smtpd_milters = [
"unix:${config.myServices.mail.milters.sockets.opendkim}"
"unix:${config.myServices.mail.milters.sockets.openarc}"
"unix:${config.myServices.mail.milters.sockets.opendmarc}"
];
};
enable = true;
enableSmtp = true;
enableSubmission = false;
destination = ["localhost"];
# This needs to reverse DNS
hostname = config.hostEnv.fqdn;
setSendmail = false;
sslCert = "/var/lib/acme/mail/fullchain.pem";
sslKey = "/var/lib/acme/mail/key.pem";
recipientDelimiter = "+";
};
};
}