Merge options virtualAccountAliases and virtualDomainAliases into virtualAliases
This commit is contained in:
parent
faf6f549b0
commit
a1e87f70fa
3 changed files with 49 additions and 57 deletions
|
|
@ -126,43 +126,43 @@ in {
|
||||||
default = {};
|
default = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
virtualDomainAliases = lib.mkOption {
|
virtualAliases = lib.mkOption {
|
||||||
type = with lib.types; attrsOf str;
|
|
||||||
example = {
|
|
||||||
"aliasdomain.com" = "domain.com";
|
|
||||||
};
|
|
||||||
description = ''
|
|
||||||
Virtual aliasing of domains. A virtual alias `"aliasdomain.com" = "domain.com"`
|
|
||||||
means that all mail directed at `@aliasdomain.com` are forwarded to `@domain.com`.
|
|
||||||
This also entails, that any account or alias of `domain.com` is partially valid
|
|
||||||
for `aliasdomain.com`. For example, `user@domain.com` can receive mails at
|
|
||||||
`user@aliasdomain.com`. However, if `user@domain.com` shall be able to dispatch
|
|
||||||
mails using `user@aliasdomain.com`, an explicit alias needs to be configured.
|
|
||||||
'';
|
|
||||||
default = {};
|
|
||||||
};
|
|
||||||
|
|
||||||
virtualAccountAliases = lib.mkOption {
|
|
||||||
type = let
|
type = let
|
||||||
|
isAccount = value: builtins.elem value (builtins.attrNames cfg.accounts);
|
||||||
|
isDomain = value: !(lib.hasInfix "@" value) && (builtins.elem value cfg.domains);
|
||||||
account = lib.mkOptionType {
|
account = lib.mkOptionType {
|
||||||
name = "Mail Account";
|
name = "Mail Account";
|
||||||
check = account: builtins.elem account (builtins.attrNames cfg.accounts);
|
check = isAccount;
|
||||||
|
};
|
||||||
|
accountOrDomain = lib.mkOptionType {
|
||||||
|
name = "Mail Account or Domain";
|
||||||
|
check = value: (isAccount value) || (isDomain value);
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
with lib.types; attrsOf (either account (nonEmptyListOf account));
|
with lib.types; attrsOf (either (nonEmptyListOf account) accountOrDomain);
|
||||||
example = {
|
example = {
|
||||||
"info@example.com" = "user1@example.com";
|
"info@example.com" = "user1@example.com";
|
||||||
"postmaster@example.com" = "user1@example.com";
|
"postmaster@example.com" = "user1@example.com";
|
||||||
"abuse@example.com" = "user1@example.com";
|
"abuse@example.com" = "user1@example.com";
|
||||||
"multi@example.com" = ["user1@example.com" "user2@example.com"];
|
"multi@example.com" = ["user1@example.com" "user2@example.com"];
|
||||||
|
"aliasdomain.com" = "domain.com";
|
||||||
};
|
};
|
||||||
description = ''
|
description = ''
|
||||||
Virtual account aliases. A virtual alias `"info@example.com" = "user1@example.com"`
|
Virtual account and domain aliases. A virtual alias means, that all mail directed
|
||||||
means that all mail to `info@example.com` is forwarded to `user1@example.com`.
|
at a given target are forwarded to the specified other destinations, too.
|
||||||
Furthermore, it also allows the user `user1@example.com` to send emails as
|
|
||||||
`info@example.com`. It is also possible to create an alias for multiple accounts.
|
For account aliases, this means that, e.g., `"user1@example.com"` receives all mail
|
||||||
In this example, all mails for `multi@example.com` will be forwarded to both
|
sent to `"info@example.com"`. In addition, `"user1@example.com"` is also able to
|
||||||
`user1@example.com` and `user2@example.com`.
|
impersonate `"info@example.com"` when sending mails. It is also possible to create
|
||||||
|
an alias for multiple accounts. In this example, all mails for `"multi@example.com"`
|
||||||
|
will be forwarded to both
|
||||||
|
`"user1@example.com"` and `"user2@example.com"`.
|
||||||
|
|
||||||
|
For domain aliases, this means that all mails directed at an aliased domain, e.g.,
|
||||||
|
`"aliasdomain.com"` are forwarded to `"domain.com"` This also entails, that any
|
||||||
|
account or alias of `"domain.com"` receives mails directed at `"aliasdomain.com"`.
|
||||||
|
However, if `"user@domain.com"` shall be able to send mails using
|
||||||
|
`"user@aliasdomain.com"`, an explicit alias needs to be configured.
|
||||||
'';
|
'';
|
||||||
default = {};
|
default = {};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -15,33 +15,27 @@ with (import ./common.nix {inherit config;}); let
|
||||||
mergeLookupTables lookupTables;
|
mergeLookupTables lookupTables;
|
||||||
|
|
||||||
lookupTableToString = attrs: let
|
lookupTableToString = attrs: let
|
||||||
valueToString = value: lib.concatStringsSep ", " value;
|
isDomain = value: !(lib.hasInfix "@" value);
|
||||||
|
valueToString = value:
|
||||||
|
if (isDomain value)
|
||||||
|
then "@${value}"
|
||||||
|
else value;
|
||||||
|
listToString = list: lib.concatStringsSep ", " (map valueToString list);
|
||||||
in
|
in
|
||||||
lib.concatStringsSep "\n" (lib.mapAttrsToList (name: value: "${name} ${valueToString value}") attrs);
|
lib.concatStringsSep "\n" (lib.mapAttrsToList (name: list: "${valueToString name} ${listToString list}") attrs);
|
||||||
|
|
||||||
mergeLookupTables = tables: lib.zipAttrsWith (n: v: lib.flatten v) tables;
|
mergeLookupTables = tables: lib.zipAttrsWith (n: v: lib.flatten v) tables;
|
||||||
|
|
||||||
virtual_accounts = mergeLookupTables (lib.map (name: {"${name}" = name;}) (lib.attrNames cfg.accounts));
|
virtual_accounts = mergeLookupTables (lib.map (name: {"${name}" = name;}) (lib.attrNames cfg.accounts));
|
||||||
virtual_account_aliases = attrsToLookupTable cfg.virtualAccountAliases;
|
virtual_aliases = attrsToLookupTable cfg.virtualAliases;
|
||||||
|
all_virtual_aliases = mergeLookupTables [virtual_accounts virtual_aliases];
|
||||||
virtual_domain_aliases = let
|
|
||||||
alias_domains = lib.mapAttrs' (src: dst: lib.nameValuePair "@${src}" "@${dst}") cfg.virtualDomainAliases;
|
|
||||||
in
|
|
||||||
attrsToLookupTable alias_domains;
|
|
||||||
|
|
||||||
all_virtual_aliases = mergeLookupTables [virtual_accounts virtual_account_aliases virtual_domain_aliases];
|
|
||||||
|
|
||||||
|
# File containing all mappings of aliases/authenticated accounts and their sender mail addresses.
|
||||||
aliases_file = let
|
aliases_file = let
|
||||||
content = lookupTableToString all_virtual_aliases;
|
content = lookupTableToString all_virtual_aliases;
|
||||||
in
|
in
|
||||||
builtins.toFile "virtual_aliases" content;
|
builtins.toFile "virtual_aliases" content;
|
||||||
|
|
||||||
# File containing all mappings of authenticated accounts and their sender mail addresses.
|
|
||||||
virtual_accounts_file = let
|
|
||||||
content = lookupTableToString all_virtual_aliases;
|
|
||||||
in
|
|
||||||
builtins.toFile "virtual_accounts" content;
|
|
||||||
|
|
||||||
virtual_domains_file = builtins.toFile "virtual_domains" (lib.concatStringsSep "\n" cfg.domains);
|
virtual_domains_file = builtins.toFile "virtual_domains" (lib.concatStringsSep "\n" cfg.domains);
|
||||||
|
|
||||||
denied_recipients = map (account: "${account.name} REJECT ${account.rejectMessage}") (lib.filter (account: account.isSystemUser) (lib.attrValues cfg.accounts));
|
denied_recipients = map (account: "${account.name} REJECT ${account.rejectMessage}") (lib.filter (account: account.isSystemUser) (lib.attrValues cfg.accounts));
|
||||||
|
|
@ -67,14 +61,15 @@ with (import ./common.nix {inherit config;}); let
|
||||||
tls_exclude_ciphers = "MD5, DES, ADH, RC4, PSD, SRP, 3DES, eNULL, aNULL";
|
tls_exclude_ciphers = "MD5, DES, ADH, RC4, PSD, SRP, 3DES, eNULL, aNULL";
|
||||||
in {
|
in {
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
assertions =
|
assertions = let
|
||||||
lib.mapAttrsToList (
|
isDomain = value: !lib.hasInfix "@" value;
|
||||||
src: dst: {
|
aliasedDomains = builtins.filter isDomain (builtins.attrNames cfg.virtualAliases);
|
||||||
assertion = (builtins.elem src cfg.domains) && (builtins.elem dst cfg.domains);
|
in
|
||||||
message = "Both aliased domain (${src}) and actual domain (${dst}) need to be managed by the mailserver.";
|
map (domain: {
|
||||||
}
|
assertion = builtins.elem domain cfg.domains;
|
||||||
)
|
message = "The domain to be aliased (${domain}) must be managed by the mailserver.";
|
||||||
cfg.virtualDomainAliases;
|
})
|
||||||
|
aliasedDomains;
|
||||||
|
|
||||||
services.postfix = {
|
services.postfix = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
@ -86,9 +81,7 @@ in {
|
||||||
|
|
||||||
enableSubmissions = true;
|
enableSubmissions = true;
|
||||||
|
|
||||||
# TODO: create function to simplify this?
|
|
||||||
mapFiles."virtual_aliases" = aliases_file;
|
mapFiles."virtual_aliases" = aliases_file;
|
||||||
mapFiles."virtual_accounts" = virtual_accounts_file;
|
|
||||||
mapFiles."denied_recipients" = denied_recipients_file;
|
mapFiles."denied_recipients" = denied_recipients_file;
|
||||||
virtual = lookupTableToString all_virtual_aliases;
|
virtual = lookupTableToString all_virtual_aliases;
|
||||||
|
|
||||||
|
|
@ -100,8 +93,7 @@ in {
|
||||||
smtpd_sasl_security_options = "noanonymous";
|
smtpd_sasl_security_options = "noanonymous";
|
||||||
smtpd_sasl_local_domain = "$myhostname";
|
smtpd_sasl_local_domain = "$myhostname";
|
||||||
smtpd_client_restrictions = "permit_sasl_authenticated,reject";
|
smtpd_client_restrictions = "permit_sasl_authenticated,reject";
|
||||||
# use mappedFile -> different path?
|
smtpd_sender_login_maps = mappedFile "virtual_aliases";
|
||||||
smtpd_sender_login_maps = "hash:/etc/postfix/virtual_accounts";
|
|
||||||
smtpd_sender_restrictions = "reject_sender_login_mismatch";
|
smtpd_sender_restrictions = "reject_sender_login_mismatch";
|
||||||
smtpd_recipient_restrictions = "reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject";
|
smtpd_recipient_restrictions = "reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject";
|
||||||
cleanup_service_name = "submission-header-cleanup";
|
cleanup_service_name = "submission-header-cleanup";
|
||||||
|
|
|
||||||
|
|
@ -42,13 +42,13 @@ in
|
||||||
fqdn = "mail.example.com";
|
fqdn = "mail.example.com";
|
||||||
domains = ["example.com" "aliased.com" "otherdomain.com"];
|
domains = ["example.com" "aliased.com" "otherdomain.com"];
|
||||||
accounts = mkAccounts accounts;
|
accounts = mkAccounts accounts;
|
||||||
virtualDomainAliases = {
|
virtualAliases = {
|
||||||
|
# domain aliases
|
||||||
"aliased.com" = "example.com";
|
"aliased.com" = "example.com";
|
||||||
};
|
# account aliases
|
||||||
virtualAccountAliases = {
|
|
||||||
"alias@example.com" = accounts."alias".address;
|
"alias@example.com" = accounts."alias".address;
|
||||||
"multi-alias@example.com" = lib.map (x: accounts.${x}.address) ["multi-alias1" "multi-alias2"];
|
"multi-alias@example.com" = lib.map (x: accounts.${x}.address) ["multi-alias1" "multi-alias2"];
|
||||||
"@example.com" = accounts."catchall".address;
|
"example.com" = accounts."catchall".address;
|
||||||
"user@otherdomain.com" = accounts."otherdomain".address;
|
"user@otherdomain.com" = accounts."otherdomain".address;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue