Merge branch 'dovecot-rfc42' into 'main'

dovecot: migrate to settings option

See merge request simple-nixos-mailserver/nixos-mailserver!498
This commit is contained in:
Martin Weinelt
2026-04-12 23:25:29 +00:00
6 changed files with 307 additions and 247 deletions
+47 -12
View File
@@ -137,6 +137,35 @@ in
description = "Message size limit enforced by Postfix."; description = "Message size limit enforced by Postfix.";
}; };
quota = {
enable = mkOption {
type = types.bool;
default = true;
description = ''
Whether to enable quota support.
When enabled, incoming mail can be rejected if a mailbox exceeds its
quota.
'';
};
defaults = {
perUser = mkOption {
type = with types; nullOr str;
default = null;
example = "10G";
description = ''
Default quota applied to all users.
The value must use a size format like `500M`, `2G`, `10G`.
If set to `null`, no default per user quota is applied and only
explicit per user quotas apply, if set.
'';
};
};
};
accounts = mkOption { accounts = mkOption {
type = types.attrsOf ( type = types.attrsOf (
types.submodule ( types.submodule (
@@ -260,8 +289,11 @@ in
default = null; default = null;
example = "2G"; example = "2G";
description = '' description = ''
Per user quota rules. Accepted sizes are `xx k/M/G/T` with the The quota limit for this user.
obvious meaning. Leave blank for the standard quota `100G`.
The value is must use a size format like `500M`, `2G`, `10G`.
If unset, will fall back to {option}`mailserver.quota.defaults.perUser` if set.
''; '';
}; };
@@ -654,11 +686,8 @@ in
}; };
lmtpSaveToDetailMailbox = mkOption { lmtpSaveToDetailMailbox = mkOption {
type = types.enum [ type = types.bool;
"yes" default = true;
"no"
];
default = "yes";
description = '' description = ''
If an email address is delimited by a "+", should it be filed into a If an email address is delimited by a "+", should it be filed into a
mailbox matching the string after the "+"? For example, mailbox matching the string after the "+"? For example,
@@ -882,25 +911,31 @@ in
mailboxes = mkOption { mailboxes = mkOption {
description = '' description = ''
The mailboxes for dovecot. The default mailboxes for Dovecot maildirs.
The [`special_use`] option must refer to an [RFC6154 2] attribute and lead with an escaped backslash.
Depending on the mail client used it might be necessary to change some mailbox's name. Depending on the mail client used it might be necessary to change some mailbox's name.
[special_use]: https://doc.dovecot.org/2.3/configuration_manual/namespace/#core_setting-namespace/mailbox/special_use
[RFC6154 2]: https://datatracker.ietf.org/doc/html/rfc6154.html#section-2
''; '';
default = { default = {
Trash = { Trash = {
auto = "no"; auto = "no";
specialUse = "Trash"; special_use = "\\Trash";
}; };
Junk = { Junk = {
auto = "subscribe"; auto = "subscribe";
specialUse = "Junk"; special_use = "\\Junk";
}; };
Drafts = { Drafts = {
auto = "subscribe"; auto = "subscribe";
specialUse = "Drafts"; special_use = "\\Drafts";
}; };
Sent = { Sent = {
auto = "subscribe"; auto = "subscribe";
specialUse = "Sent"; special_use = "\\Sent";
}; };
}; };
}; };
Generated
+3 -3
View File
@@ -79,11 +79,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1774935083, "lastModified": 1776030597,
"narHash": "sha256-Mh6bLcYAcENBAZk3RoMPMFCGGMZmfaGMERE4siZOgP4=", "narHash": "sha256-H2CYM/RmVqCo1iud5BhPp8Pim2d1ESGt2FDHjbmju8A=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "2f4fd5e1abf9bac8c1d22750c701a7a5e6b524c6", "rev": "c88e63f4caf12c731f61ce71f300680ce73c180e",
"type": "github" "type": "github"
}, },
"original": { "original": {
+253 -231
View File
@@ -32,6 +32,16 @@ with (import ./common.nix {
}); });
let let
inherit (lib)
attrNames
concatMapStringsSep
filterAttrs
mapAttrs'
mkForce
mkIf
nameValuePair
;
cfg = config.mailserver; cfg = config.mailserver;
passwdDir = "/run/dovecot2"; passwdDir = "/run/dovecot2";
@@ -39,8 +49,6 @@ let
userdbFile = "${passwdDir}/userdb"; userdbFile = "${passwdDir}/userdb";
# This file contains the ldap bind password # This file contains the ldap bind password
ldapConfFile = "${passwdDir}/dovecot-ldap.conf.ext"; ldapConfFile = "${passwdDir}/dovecot-ldap.conf.ext";
boolToYesNo = x: if x then "yes" else "no";
listToLine = lib.concatStringsSep " ";
listToMultiAttrs = listToMultiAttrs =
keyPrefix: attrs: keyPrefix: attrs:
lib.listToAttrs ( lib.listToAttrs (
@@ -53,14 +61,6 @@ let
maildirLayoutAppendix = lib.optionalString (cfg.storage.directoryLayout == "fs") ":LAYOUT=fs"; maildirLayoutAppendix = lib.optionalString (cfg.storage.directoryLayout == "fs") ":LAYOUT=fs";
maildirUTF8FolderNames = lib.optionalString cfg.useUTF8FolderNames ":UTF-8"; maildirUTF8FolderNames = lib.optionalString cfg.useUTF8FolderNames ":UTF-8";
# https://doc.dovecot.org/2.3/configuration_manual/home_directories_for_virtual_users/#ways-to-set-up-home-directory
# Mail directory below the home directory
dovecotMaildir =
"maildir:~/mail${maildirLayoutAppendix}${maildirUTF8FolderNames}"
+ (lib.optionalString (cfg.indexDir != null) ":INDEX=${cfg.indexDir}/%{domain}/%{username}");
postfixCfg = config.services.postfix;
ldapConfig = pkgs.writeTextFile { ldapConfig = pkgs.writeTextFile {
name = "dovecot-ldap.conf.ext.template"; name = "dovecot-ldap.conf.ext.template";
text = '' text = ''
@@ -128,12 +128,13 @@ let
lib.mapAttrsToList ( lib.mapAttrsToList (
name: _: name: _:
if lib.elem name accountsWithPlaintextPasswordFiles then if lib.elem name accountsWithPlaintextPasswordFiles then
"${name}:${"$(sed -n '1{p;p;q}' ${passwordFiles."${name}"} | ${lib.getExe' pkgs.dovecot "doveadm"} pw)"}::::::" "${name}:${"$(sed -n '1{p;p;q}' ${passwordFiles."${name}"} | ${lib.getExe' config.services.dovecot2.package "doveadm"} pw)"}::::::"
else else
"${name}:${"$(head -n 1 ${passwordFiles."${name}"})"}::::::" "${name}:${"$(head -n 1 ${passwordFiles."${name}"})"}::::::"
) cfg.accounts ) cfg.accounts
)} )}
EOF EOF
chown dovecot2:dovecot2 ${passwdFile}
cat <<EOF > ${userdbFile} cat <<EOF > ${userdbFile}
${lib.concatStringsSep "\n" ( ${lib.concatStringsSep "\n" (
@@ -144,10 +145,11 @@ let
) cfg.accounts ) cfg.accounts
)} )}
EOF EOF
chown dovecot2:dovecot2 ${userdbFile}
''; '';
junkMailboxes = builtins.attrNames ( junkMailboxes = builtins.attrNames (
lib.filterAttrs (_: v: v ? "specialUse" && v.specialUse == "Junk") cfg.mailboxes lib.filterAttrs (_: v: v ? "special_use" && v.special_use == "\\Junk") cfg.mailboxes
); );
junkMailboxNumber = builtins.length junkMailboxes; junkMailboxNumber = builtins.length junkMailboxes;
# The assertion guarantees there is exactly one Junk mailbox. # The assertion guarantees there is exactly one Junk mailbox.
@@ -163,30 +165,29 @@ let
else else
scope scope
); );
ftsPluginSettings = {
fts = "flatcurve";
fts_languages = listToLine cfg.fullTextSearch.languages;
fts_tokenizers = listToLine [
"generic"
"email-address"
];
fts_tokenizer_email_address = "maxlen=100"; # default 254 too large for Xapian
fts_flatcurve_substring_search = boolToYesNo cfg.fullTextSearch.substringSearch;
fts_filters = listToLine cfg.fullTextSearch.filters;
fts_header_excludes = listToLine cfg.fullTextSearch.headerExcludes;
fts_autoindex = boolToYesNo cfg.fullTextSearch.autoIndex;
fts_enforced = cfg.fullTextSearch.enforced;
}
// (listToMultiAttrs "fts_autoindex_exclude" cfg.fullTextSearch.autoIndexExclude);
in in
{ {
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
assertions = [ assertions = [
{ {
assertion = junkMailboxNumber == 1; assertion = junkMailboxNumber == 1;
message = "nixos-mailserver requires exactly one dovecot mailbox with the 'special use' flag set to 'Junk' (${builtins.toString junkMailboxNumber} have been found)"; message = "nixos-mailserver requires exactly one dovecot mailbox with the 'special_use' flag set to '\\Junk' (${builtins.toString junkMailboxNumber} have been found)";
}
{
assertion =
let
usersWithQuota = attrNames (
filterAttrs (_: account: account.quota != null) config.mailserver.loginAccounts
);
in
!cfg.quota.enable -> usersWithQuota == { };
message = ''
Without quota support enabled, per-user quotas cannot be applied to the following accounts:
${concatMapStringsSep "\n" (account: "- ${account}") quotaUsers}
Either remove per user quota settings or re-enable `mailserver.quota.enable`.
'';
} }
]; ];
@@ -215,7 +216,7 @@ in
# the global config and tries to open shared libraries configured in there, # the global config and tries to open shared libraries configured in there,
# which are usually not compatible. # which are usually not compatible.
environment.systemPackages = [ environment.systemPackages = [
pkgs.dovecot_pigeonhole pkgs.dovecot_pigeonhole_0_5
] ]
++ lib.optional cfg.fullTextSearch.enable pkgs.dovecot-fts-flatcurve; ++ lib.optional cfg.fullTextSearch.enable pkgs.dovecot-fts-flatcurve;
@@ -223,30 +224,9 @@ in
environment.etc."dovecot/modules".source = "/run/current-system/sw/lib/dovecot/modules"; environment.etc."dovecot/modules".source = "/run/current-system/sw/lib/dovecot/modules";
services.dovecot2 = { services.dovecot2 = {
package = pkgs.dovecot_2_3;
enable = true; enable = true;
enableImap = cfg.enableImap || cfg.enableImapSsl; enablePAM = mkForce false;
enablePop3 = cfg.enablePop3 || cfg.enablePop3Ssl;
enablePAM = false;
enableQuota = true;
mailGroup = cfg.storage.group;
mailUser = cfg.storage.owner;
mailLocation = dovecotMaildir;
sslServerCert = x509CertificateFile;
sslServerKey = x509PrivateKeyFile;
enableDHE = lib.mkDefault false;
enableLmtp = true;
mailPlugins.globally.enable = lib.optionals cfg.fullTextSearch.enable [
"fts"
"fts_flatcurve"
];
protocols = lib.optional cfg.enableManageSieve "sieve";
pluginSettings = {
sieve = "file:${cfg.sieveDirectory}/%{user}/scripts;active=${cfg.sieveDirectory}/%{user}/active.sieve";
sieve_default = "file:${cfg.sieveDirectory}/%{user}/default.sieve";
sieve_default_name = "default";
}
// (lib.optionalAttrs cfg.fullTextSearch.enable ftsPluginSettings);
sieve = { sieve = {
extensions = [ extensions = [
@@ -285,196 +265,238 @@ in
} }
]; ];
mailboxes = cfg.mailboxes; settings = {
# vmail user
mail_uid = cfg.storage.owner;
mail_gid = cfg.storage.group;
mail_access_groups = cfg.storage.group;
extraConfig = '' # authentication
#Extra Config auth_mechanisms = [
${lib.optionalString cfg.debug.dovecot '' "plain"
mail_debug = yes "login"
auth_debug = yes ];
verbose_ssl = yes disable_plaintext_auth = true;
''}
${lib.optionalString (cfg.enableImap || cfg.enableImapSsl) '' # backend services
service imap-login { "service auth" = {
inet_listener imap { "unix_listener auth" = {
${ mode = "0660";
if cfg.enableImap then user = config.services.postfix.user;
'' group = config.services.postfix.group;
port = 143 };
'' };
else "service indexer-worker" = mkIf (cfg.fullTextSearch.memoryLimit != null) {
'' vsz_limit = "${toString cfg.fullTextSearch.memoryLimit} MB";
# see https://dovecot.org/pipermail/dovecot/2010-March/047479.html };
port = 0 "service lmtp" = {
'' "unix_listener dovecot-lmtp" = {
} group = config.services.postfix.group;
} mode = "0600";
inet_listener imaps { user = config.services.postfix.user;
${ };
if cfg.enableImapSsl then user = cfg.storage.owner;
'' vsz_limit = "${toString cfg.lmtpMemoryLimit} MB";
port = 993 };
ssl = yes "service quota-status" = mkIf cfg.quota.enable {
'' executable = toString [
else "${config.services.dovecot2.package}/libexec/dovecot/quota-status"
'' "-p"
# see https://dovecot.org/pipermail/dovecot/2010-March/047479.html "postfix"
port = 0 ];
'' "unix_listener quota-status" = {
} user = "postfix";
} };
} client_limit = 1;
''} vsz_limit = "${toString cfg.quotaStatusMemoryLimit} MB";
${lib.optionalString (cfg.enablePop3 || cfg.enablePop3Ssl) '' };
service pop3-login {
inet_listener pop3 {
${
if cfg.enablePop3 then
''
port = 110
''
else
''
# see https://dovecot.org/pipermail/dovecot/2010-March/047479.html
port = 0
''
}
}
inet_listener pop3s {
${
if cfg.enablePop3Ssl then
''
port = 995
ssl = yes
''
else
''
# see https://dovecot.org/pipermail/dovecot/2010-March/047479.html
port = 0
''
}
}
}
''}
protocol imap { # frontend services
mail_max_userip_connections = ${toString cfg.maxConnectionsPerUser} "service imap-login" = mkIf (cfg.enableImap || cfg.enableImapSsl) {
mail_plugins = $mail_plugins imap_sieve "inet_listener imap" = {
} # see https://dovecot.org/pipermail/dovecot/2010-March/047479.html
port = if cfg.enableImap then 143 else 0;
};
"inet_listener imaps" = {
# see https://dovecot.org/pipermail/dovecot/2010-March/047479.html
port = if cfg.enableImapSsl then 993 else 0;
ssl = true;
};
};
"service pop3-login" = mkIf (cfg.enablePop3 || cfg.enablePop3Ssl) {
"inet_listener pop3" = {
# see https://dovecot.org/pipermail/dovecot/2010-March/047479.html
port = if cfg.enablePop3 then 110 else 0;
};
"inet_listener pop3s" = {
# see https://dovecot.org/pipermail/dovecot/2010-March/047479.html
port = if cfg.enablePop3Ssl then 995 else 0;
ssl = true;
};
};
"service imap" = {
vsz_limit = "${toString cfg.imapMemoryLimit} MB";
};
service imap { # protocols
vsz_limit = ${builtins.toString cfg.imapMemoryLimit} MB protocols = [
} "lmtp"
]
++ lib.optionals (cfg.enableImap || cfg.enableImapSsl) [ "imap" ]
++ lib.optionals (cfg.enablePop3 || cfg.enablePop3Ssl) [ "pop3" ]
++ lib.optionals cfg.enableManageSieve [ "sieve" ];
protocol pop3 { "protocol lmtp" = {
mail_max_userip_connections = ${toString cfg.maxConnectionsPerUser} mail_plugins = [
} "$mail_plugins"
"sieve"
mail_access_groups = ${cfg.storage.group} ];
};
# https://ssl-config.mozilla.org/#server=dovecot&version=2.3.21&config=intermediate&openssl=3.4.1&guideline=5.7 "protocol imap" = {
ssl = required mail_max_userip_connections = cfg.maxConnectionsPerUser;
ssl_min_protocol = TLSv1.2 mail_plugins = [
ssl_prefer_server_ciphers = no "$mail_plugins"
ssl_cipher_list = ${ "imap_sieve"
lib.concatStringsSep ":" [
# TLS1.3
"TLS_AES_128_GCM_SHA256"
"TLS_CHACHA20_POLY1305_SHA256"
"TLS_AES_256_GCM_SHA384"
# TLS1.2
# EC key material
"ECDHE-ECDSA-AES128-GCM-SHA256"
"ECDHE-ECDSA-CHACHA20-POLY1305"
"ECDHE-ECDSA-AES256-GCM-SHA384"
# RSA key material
"ECDHE-RSA-AES128-GCM-SHA256"
"ECDHE-RSA-CHACHA20-POLY1305"
"ECDHE-RSA-AES256-GCM-SHA384"
] ]
} ++ lib.optionals cfg.quota.enable [
ssl_curve_list = X25519MLKEM768:X25519:prime256v1:secp384r1 "imap_quota"
];
};
"protocol pop3" = {
mail_max_userip_connections = cfg.maxConnectionsPerUser;
};
service lmtp { # globally enabled plugins
unix_listener dovecot-lmtp { mail_plugins = [
group = ${postfixCfg.group} "$mail_plugins"
mode = 0600 ]
user = ${postfixCfg.user} ++ lib.optionals cfg.quota.enable [
"quota"
]
++ lib.optionals cfg.fullTextSearch.enable [
"fts"
"fts_flatcurve"
];
# tls settings
ssl_cert = "<${x509CertificateFile}";
ssl_key = "<${x509PrivateKeyFile}";
# https://ssl-config.mozilla.org/#server=dovecot&version=2.3.21&config=intermediate&openssl=3.4.1&guideline=5.7
ssl = "required";
ssl_min_protocol = "TLSv1.2";
ssl_prefer_server_ciphers = false;
ssl_cipher_list = lib.concatStringsSep ":" [
# TLS1.3
"TLS_AES_128_GCM_SHA256"
"TLS_CHACHA20_POLY1305_SHA256"
"TLS_AES_256_GCM_SHA384"
# TLS1.2
# EC key material
"ECDHE-ECDSA-AES128-GCM-SHA256"
"ECDHE-ECDSA-CHACHA20-POLY1305"
"ECDHE-ECDSA-AES256-GCM-SHA384"
# RSA key material
"ECDHE-RSA-AES128-GCM-SHA256"
"ECDHE-RSA-CHACHA20-POLY1305"
"ECDHE-RSA-AES256-GCM-SHA384"
];
ssl_curve_list = lib.concatStringsSep ":" [
"X25519MLKEM768"
"X25519"
"prime256v1"
"secp384r1"
];
# default mail storage
# https://doc.dovecot.org/2.3/configuration_manual/home_directories_for_virtual_users/#ways-to-set-up-home-directory
mail_location =
"maildir:~/mail${maildirLayoutAppendix}${maildirUTF8FolderNames}"
+ (lib.optionalString (cfg.indexDir != null) ":INDEX=${cfg.indexDir}/%{domain}/%{username}");
passdb = [
{
driver = "passwd-file";
args = "${passwdFile}";
} }
vsz_limit = ${builtins.toString cfg.lmtpMemoryLimit} MB ]
} ++ lib.optionals cfg.ldap.enable [
{
service quota-status { driver = "ldap";
inet_listener { args = "${ldapConfFile}";
port = 0
} }
unix_listener quota-status { ];
user = postfix userdb = [
{
driver = "passwd-file";
args = "${userdbFile}";
default_fields = [
"home=${cfg.storage.path}/%{domain}/%{username}"
"uid=${builtins.toString cfg.storage.uid}"
"gid=${builtins.toString cfg.storage.gid}"
];
} }
vsz_limit = ${builtins.toString cfg.quotaStatusMemoryLimit} MB ]
} ++ lib.optionals cfg.ldap.enable [
{
recipient_delimiter = ${cfg.recipientDelimiter} driver = "ldap";
lmtp_save_to_detail_mailbox = ${cfg.lmtpSaveToDetailMailbox} args = "${ldapConfFile}";
override_fields = [
protocol lmtp { "uid=${toString cfg.storage.uid}"
mail_plugins = $mail_plugins sieve "gid=${toString cfg.storage.gid}"
} ];
passdb {
driver = passwd-file
args = ${passwdFile}
}
userdb {
driver = passwd-file
args = ${userdbFile}
default_fields = \
home=${cfg.storage.path}/%{domain}/%{username} \
uid=${builtins.toString cfg.storage.uid} \
gid=${builtins.toString cfg.storage.uid}
}
${lib.optionalString cfg.ldap.enable ''
passdb {
driver = ldap
args = ${ldapConfFile}
} }
];
userdb { # default user mailboxes
driver = ldap "namespace inbox" = {
args = ${ldapConfFile} inbox = true;
override_fields = \ separator = ".";
uid=${toString cfg.storage.uid} \ }
gid=${toString cfg.storage.uid} // mapAttrs' (name: value: nameValuePair ''mailbox "${name}"'' value) cfg.mailboxes;
lda_mailbox_autosubscribe = true;
lda_mailbox_autocreate = true;
# subaddressing
recipient_delimiter = cfg.recipientDelimiter;
lmtp_save_to_detail_mailbox = cfg.lmtpSaveToDetailMailbox;
plugin = {
sieve = "file:${cfg.sieveDirectory}/%{user}/scripts;active=${cfg.sieveDirectory}/%{user}/active.sieve";
sieve_default = "file:${cfg.sieveDirectory}/%{user}/default.sieve";
sieve_default_name = "default";
}
// lib.optionalAttrs cfg.fullTextSearch.enable (
{
fts = "flatcurve";
fts_languages = cfg.fullTextSearch.languages;
fts_tokenizers = [
"generic"
"email-address"
];
fts_tokenizer_email_address = "maxlen=100"; # default 254 too large for Xapian
fts_flatcurve_substring_search = cfg.fullTextSearch.substringSearch;
fts_filters = cfg.fullTextSearch.filters;
fts_header_excludes = cfg.fullTextSearch.headerExcludes;
fts_autoindex = cfg.fullTextSearch.autoIndex;
fts_enforced = cfg.fullTextSearch.enforced;
} }
''} // (listToMultiAttrs "fts_autoindex_exclude" cfg.fullTextSearch.autoIndexExclude)
)
service auth { // lib.optionalAttrs cfg.quota.enable {
unix_listener auth { quota_rule = mkIf (cfg.quota.defaults.perUser != null) "*:storage=${cfg.quota.defaults.perUser}";
mode = 0660 quota = "count:User quota"; # per virtual mail user quota
user = ${postfixCfg.user} quota_status_success = "DUNNO";
group = ${postfixCfg.group} quota_status_nouser = "DUNNO";
} quota_status_overquota = "552 5.2.2 Mailbox is full";
} quota_grace = "10%%";
quota_vsizes = true;
auth_mechanisms = plain login };
}
namespace inbox { // lib.optionalAttrs cfg.debug.dovecot {
separator = ${cfg.hierarchySeparator} mail_debug = true;
inbox = yes auth_debug = true;
} verbose_ssl = true;
};
service indexer-worker {
${lib.optionalString (cfg.fullTextSearch.memoryLimit != null) ''
vsz_limit = ${toString (cfg.fullTextSearch.memoryLimit * 1024 * 1024)}
''}
}
lda_mailbox_autosubscribe = yes
lda_mailbox_autocreate = yes
'';
}; };
systemd.services.dovecot = { systemd.services.dovecot = {
+1 -1
View File
@@ -27,7 +27,7 @@ in
{ {
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
dovecot config.services.dovecot2.package
openssh openssh
postfix postfix
rspamd rspamd
+2
View File
@@ -373,6 +373,8 @@ in
# reject selected recipients # reject selected recipients
"check_recipient_access ${mappedFile "denied_recipients"}" "check_recipient_access ${mappedFile "denied_recipients"}"
"check_recipient_access ${mappedFile "reject_recipients"}" "check_recipient_access ${mappedFile "reject_recipients"}"
]
++ lib.optionals cfg.quota.enable [
# quota checking # quota checking
"check_policy_service unix:/run/dovecot2/quota-status" "check_policy_service unix:/run/dovecot2/quota-status"
]; ];
+1
View File
@@ -33,6 +33,7 @@ groups = [
"mailserver.dmarcReporting", "mailserver.dmarcReporting",
"mailserver.tlsrpt", "mailserver.tlsrpt",
"mailserver.fullTextSearch", "mailserver.fullTextSearch",
"mailserver.quota",
"mailserver.redis", "mailserver.redis",
"mailserver.ldap", "mailserver.ldap",
"mailserver.monitoring", "mailserver.monitoring",