ansible-mailserver-debian/mail_system/templates/dovecot/local.conf

485 lines
11 KiB
Text
Raw Permalink Normal View History

2026-03-22 13:09:26 +01:00
# THIS FILE IS CONTROLLED BY ANSIBLE - DO NOT CHANGE IN DEPLOYMENT!
# dovecot config
# Note: debian has some settings in conf.d/* that we cannot override
# (e.g. we cannot unset passdb pam), so we must disable inclusion of conf.d/*
# in dovecot.conf
# execution
mail_uid = mailstore
mail_gid = mailstore
mail_privileged_group = mailstore
default_vsz_limit = 512M
# tls
ssl = required
ssl_server {
cert_file = /etc/dovecot/private/dovecot.pem
key_file = /etc/dovecot/private/dovecot.key
}
ssl_cipher_list = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
# mail storage
mail_driver = maildir
mail_home = /srv/mailstore/%{user | domain}/%{user | username }/
mail_path = /srv/mailstore/%{user | domain}/%{user | username }/Maildir
mail_inbox_path = /srv/mailstore/%{user | domain}/%{user | username }/Maildir
mailbox_list_layout = fs
# auth
auth_verbose = yes
auth_mechanisms {
plain = yes
login = yes
}
auth_verbose = yes
auth_default_domain = {{ mailserver.dovecot.auth_default_realm }}
# auth service for postfix
service auth {
unix_listener auth-userdb {
}
unix_listener /var/spool/postfix/private/auth {
mode = 0660
user = postfix
group = postfix
}
}
service auth-worker {
}
# users and passwords: in postgresql
pgsql localhost {
parameters {
port = {{ mailserver.postgresql.port }}
user = {{ mailserver.postgresql.username }}
password = {{ mailserver.postgresql.password }}
dbname = {{ mailserver.postgresql.dbname }}
}
}
sql_driver = pgsql
passdb sql {
driver = sql
default_password_scheme = PBKDF2
query = SELECT \
users.username as user, \
domains.name as domain, \
password, \
suspend_imap_reason as nologin \
FROM users JOIN domains ON users.domain_id=domains.id \
WHERE users.username = '%{user | username}' AND domains.name = '%{user | domain }'
}
passdb_default_password_scheme = PBKDF2
userdb sql {
query = SELECT \
'/srv/mailstore/' || domains.name || '/' || users.username || '/Maildir/' as home, \
'mailstore' as uid, \
'mailstore' as gid, \
CONCAT(quota_storage_bytes, 'B') AS quota_storage_size, \
quota_inbox_messages AS quota_message_count \
FROM users JOIN domains ON users.domain_id=domains.id \
WHERE users.username = '%{user | username}' AND domains.name = '%{user | domain}'
iterate_query = SELECT \
users.username as username, \
domains.name as domain \
FROM users JOIN domains ON users.domain_id=domains.id \
ORDER BY 2,1
}
# quota
mail_plugins {
quota = yes
}
quota_storage_size = 20G
namespace inbox {
mailbox Trash {
quota_storage_extra = 100M
}
}
protocol !indexer-worker {
mail_vsize_bg_after_count = 100
}
protocol imap {
mail_plugins {
imap_quota = yes
}
}
quota "user-quota" {
storage_grace = 200M
status_success = DUNNO
status_nouser = DUNNO
status_overquota = "552 5.2.2 Mailbox is full"
exceeded_message = "User %{user} is over quota and must reduce the overall mail volume and/or the number of messages in INBOX."
warning warn-95 {
quota_storage_percentage = 95
execute quota-warning {
args = 95 %{user}
}
}
warning warn-80 {
quota_storage_percentage = 80
execute quota-warning {
args = 80 %{user}
}
}
warning warn-under {
quota_storage_percentage = 95
threshold = under
execute quota-warning {
args = below %{user}
}
}
}
service quota-warning {
executable = script /usr/local/bin/quota-warning.sh
unix_listener quota-warning {
user = dovenull
group = dovenull
mode = 0660
}
}
service quota-status {
executable = quota-status -p postfix
#unix_listener /var/spool/postfix/private/quota-status {
# user = postfix
#}
inet_listener quota-status {
port = 12480
}
client_limit = 1
}
# check:
# doveadm quota get -A
# echo -e "recipient=USER@DOMAIN\n" | nc -v 127.0.0.1 12480
# namespaces
namespace inbox {
type = private
inbox = yes
mail_driver = maildir
separator = /
mail_path = /srv/mailstore/%{user | domain}/%{user | username}/Maildir
mailbox_list_layout = fs
# location = maildir:/srv/mailstore/%%d/%%n/Maildir:LAYOUT=fs:INDEXPVT=~/shared/%%d/%%n/
subscriptions = yes
list = yes
mailbox Drafts {
special_use = \Drafts
}
mailbox Junk {
auto = subscribe
special_use = \Junk
autoexpunge = 180d
}
mailbox Trash {
auto = subscribe
special_use = \Trash
autoexpunge = 180d
}
mailbox Sent {
special_use = \Sent
}
mailbox "Sent Messages" {
special_use = \Sent
}
}
namespace shared {
type = shared
inbox = no
mail_driver = maildir
separator = /
prefix = shared/$user/
#prefix = shared/$domain/$username/
mail_path = /srv/mailstore/%{owner_user | domain}/%{owner_user | username}/Maildir
#mail_index_path = ~/shared/%{owner_user | domain}/%{owner_user | username}/
mail_index_private_path = ~/shared/%{owner_user | domain}/%{owner_user | username}/
mailbox_list_layout = fs
subscriptions = no
list = yes
}
#namespace roles {
# type = shared
# inbox = no
# mail_driver = maildir
# separator = /
# prefix = roles/
# mail_path = /srv/mailstore/role_specific/roles/Maildir
# mailbox_list_layout = fs
# mail_index_private_path = ~/role_specific/roles/
# subscriptions = no
# list = yes
#}
#namespace virtual {
# separator = /
# prefix = virtual/
# mail_path = virtual:/srv/mailstore/%{user | domain}/%{user | username}/Maildir_virtual
#}
# imap service
service imap {
}
service imap-login {
inet_listener imap {
type = imap
}
inet_listener imaps {
type = imaps
}
}
# lmtp service
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
group = postfix
mode = 0600
user = postfix
}
}
protocol lmtp {
postmaster_address = {{ mailserver.dovecot.postmaster_email }}
mail_plugins {
quota = yes
}
auth_username_format = %{user | username |lower}@%{user | domain | lower}
}
# acl
mail_plugins {
acl = yes
}
acl_driver = vfile
protocol imap {
mail_plugins {
imap_acl = yes
}
}
acl_sharing_map {
dict proxy {
name = acl
}
}
imap_acl_allow_anyone = yes
dict_server {
dict acl {
driver = sql
sql_driver = pgsql
pgsql localhost {
parameters {
port = {{ mailserver.postgresql.port }}
user = {{ mailserver.postgresql.username }}
password = {{ mailserver.postgresql.password }}
dbname = {{ mailserver.postgresql.dbname }}
}
}
dict_map shared/shared-boxes/user/$to/$from {
sql_table = shared_folders
value_field dummy {
}
key_field from_user {
value = $from
}
key_field to_user {
value = $to
}
}
dict_map shared/shared-user-boxes-rev/$from/$to {
sql_table = shared_folders
value_field dummy {
}
key_field from_user {
value = $from
}
key_field to_user {
value = $to
}
}
dict_map shared/shared-boxes/anyone/$from {
sql_table = shared_folders_anyone
value_field dummy {
}
key_field from_user {
value = $from
}
}
}
}
service dict {
unix_listener dict {
mode = 0660
user = dovecot
group = mailstore
}
}
# TODO enable in v2.4.2
#acl_dict_index = yes
# debugging:
# doveadm acl debug -u ACCESSING_USER@DOMAIN shared/SHARING_USER@DOMAIN/FOLDERNAME
# fulltext search
mail_plugins {
fts = yes
fts_flatcurve = yes
}
fts_autoindex = yes
#fts_autoindex_max_recent_msgs = 0
fts_search_add_missing = yes
language_filters = normalizer-icu snowball stopwords
language_tokenizers = generic email-address
language_tokenizer_generic_algorithm = simple
# Note: the 'language' settings is set mandatory by dovecot but has totally NO impact on FTS flatcurve module
language en {
default = yes
filters = lowercase snowball english-possessive stopwords
}
language de {
}
fts flatcurve {
substring_search = yes
}
# cf. /usr/share/doc/dovecot-fts-xapian/README.md.gz
fts flatcurve {
driver = flatcurve
autoindex = yes
}
mailbox Trash {
special_use = \Trash
fts_autoindex = no
}
mailbox Junk {
special_use = \Junk
fts_autoindex = no
}
fts_header_excludes {
* = yes
}
fts_header_includes {
From = yes
To = yes
Cc = yes
Bcc = yes
Subject = yes
Message-ID = yes
Date = yes
}
# sieve plugin
# Note: we put sieve scripts below /var/lib/dovecot/sieve/ rather than /etc,
# because dovecot may want to recompile *.svbin and writing under /etc is prohobited
# by systemd setting ProtectSystem=full
protocols {
sieve = yes
}
protocol sieve {
}
protocol lmtp {
mail_plugins {
sieve = yes
}
}
sieve_script personal {
type = personal
active_path = /srv/mailstore/%{user | domain}/%{user | username }/.dovecot.sieve
path = /srv/mailstore/%{user | domain}/%{user | username }/sieve
}
sieve_script before {
type = before
sieve_script_path = /var/lib/dovecot/sieve/before
}
sieve_script after {
type = after
sieve_script_path = /var/lib/dovecot/sieve/after
}
#sieve_user_log_path = /srv/mailstore/%{user | domain}/%{user | username }/.dovecot.sieve.log
service managesieve {
}
service managesieve-login {
inet_listener sieve {
port = 4190
}
}
# sieve-extprograms plugin
sieve_plugins {
sieve_extprograms = yes
}
sieve_global_extensions {
vnd.dovecot.pipe = yes
vnd.dovecot.filter = yes
vnd.dovecot.execute = yes
vnd.dovecot.debug = yes
}
sieve_pipe_bin_dir = /var/lib/dovecot/sieve/pipes
sieve_execute_bin_dir = /var/lib/dovecot/sieve/pipes
# imap-sieve plugin
protocol imap {
mail_plugins {
imap_sieve = yes
}
}
sieve_plugins {
sieve_imapsieve = yes
}
mailbox Junk {
sieve_script learn-spam {
type = before
cause = copy
path = /var/lib/dovecot/sieve/pipes/learn-spam.sieve
}
}
imapsieve_from Junk {
sieve_script learn-ham {
type = before
cause = copy
path = /var/lib/dovecot/sieve/pipes/learn-ham.sieve
}
}
# (disabled) service health check
# cf. https://doc.dovecot.org/main/core/config/health_check.html
#service health-check {
# executable = script -p health-check.sh
# inet_listener health-check {
# port = 5001
# }
#}
#log_debug = category=auth
#log_debug = category=imap
#log_debug = category=lmtp
#log_debug = category=fts
#log_debug = category=sieve
#log_debug = category=imapsieve
#log_debug = category=acl
#log_debug = category=dict_server
#log_debug = category=namespace
#log_debug = category=mail
# More info:
# doveadm -v service status
# See also
# * https://monospace.games/posts/20250815-dovecot-24.html
# * https://workaround.org/ispmail-trixie/
# * https://thomas-leister.de/en/mailserver-migrate-config-to-dovecot-2.4-debian-trixie/