diff --git a/dovecot/defaults/main.yml b/dovecot/defaults/main.yml
index 31ce02cdf11c4ab6962dda51bfeba72d0679e2df..144b53f60df97af437180a9059840ad9499c7f85 100644
--- a/dovecot/defaults/main.yml
+++ b/dovecot/defaults/main.yml
@@ -31,3 +31,22 @@ dovecot_dsync_host_attribute: ansible_host
 dovecot_content_filter: false
 dovecot_spam_folder: Spam
 dovecot_spam_user: "${1}"  # debian-spamd
+dovecot_sieve: 'file:~/sieve;active=~/.dovecot.sieve'
+
+# These variables were introduced for compatibility to a certain setup.
+# They may disappear without prior notice and/or may not work as expected.
+dovecot_process_limit: 100
+dovecot_client_limit: 1000
+dovecot_disable_imap_starttls: false
+dovecot_postfix_public_private_partnership: true
+dovecot_imap_idle_interval: '29 mins'
+dovecot_imap_max_userip_connections: 40
+dovecot_lda_mailbox_autocreate: false
+dovecot_lda_mailbox_autosubscribe: false
+dovecot_auth_realms: []
+dovecot_auth_default_realm: ''
+dovecot_auth_krb5_keytab: ''
+dovecot_auth_mechanisms:
+  - plain
+dovecot_mail_namespaces: []
+dovecot_special_mailbox_auto_subscribe: false
diff --git a/dovecot/tasks/main.yml b/dovecot/tasks/main.yml
index f629400b6cbfd864c508d89ebf14c416225d6852..c9af587fb3979391cc425a93207a0804266689d1 100644
--- a/dovecot/tasks/main.yml
+++ b/dovecot/tasks/main.yml
@@ -28,15 +28,18 @@
     - dovecot.conf
     - deny-users
     - conf.d/10-auth.conf
+    - conf.d/10-director.conf
     - conf.d/10-mail.conf
     - conf.d/10-master.conf
     - conf.d/10-ssl.conf
     - conf.d/15-lda.conf
-    - conf.d/20-managesieve.conf
+    - conf.d/15-mailboxes.conf
     - conf.d/20-imap.conf
     - conf.d/20-lmtp.conf
+    - conf.d/20-managesieve.conf
     - conf.d/90-sieve.conf
     - conf.d/auth-passwdfile.conf.ext
+    - conf.d/auth-system.conf.ext
   notify:
     - restart dovecot
   tags:
diff --git a/dovecot/templates/conf.d/10-auth.conf.j2 b/dovecot/templates/conf.d/10-auth.conf.j2
index 5daa65effa3ee600088fce4e76e49809ff707655..7c8a79ad7f073bb107230f7b33aa4900268e45b0 100644
--- a/dovecot/templates/conf.d/10-auth.conf.j2
+++ b/dovecot/templates/conf.d/10-auth.conf.j2
@@ -26,11 +26,11 @@ disable_plaintext_auth = yes
 # them. You can leave it empty if you don't want to support multiple realms.
 # Many clients simply use the first one listed here, so keep the default realm
 # first.
-#auth_realms =
+auth_realms = {{ dovecot_auth_realms|join(" ") }}
 
 # Default realm/domain to use if none was specified. This is used for both
 # SASL realms and appending @domain to username in plaintext logins.
-#auth_default_realm = 
+auth_default_realm = {{ dovecot_auth_default_realm }}
 
 # List of allowed characters in username. If the user-given username contains
 # a character not listed in here, the login automatically fails. This is just
@@ -77,7 +77,7 @@ auth_username_format = %Ln
 # Kerberos keytab to use for the GSSAPI mechanism. Will use the system
 # default (usually /etc/krb5.keytab) if not specified. You may need to change
 # the auth service to run as root to be able to read this file.
-#auth_krb5_keytab = 
+auth_krb5_keytab = {{ dovecot_auth_krb5_keytab }}
 
 # Do NTLM and GSS-SPNEGO authentication using Samba's winbind daemon and
 # ntlm_auth helper. <doc/wiki/Authentication/Mechanisms/Winbind.txt>
@@ -101,7 +101,7 @@ auth_username_format = %Ln
 #   plain login digest-md5 cram-md5 ntlm rpa apop anonymous gssapi otp
 #   gss-spnego
 # NOTE: See also disable_plaintext_auth setting.
-auth_mechanisms = plain
+auth_mechanisms = {{ dovecot_auth_mechanisms|join(" ") }}
 
 ##
 ## Password and user databases
diff --git a/dovecot/templates/conf.d/10-director.conf.j2 b/dovecot/templates/conf.d/10-director.conf.j2
new file mode 100644
index 0000000000000000000000000000000000000000..1429e2c2f71244ad6334083b15d5079e6d8a04ca
--- /dev/null
+++ b/dovecot/templates/conf.d/10-director.conf.j2
@@ -0,0 +1,57 @@
+##
+## Director-specific settings.
+##
+
+# Director can be used by Dovecot proxy to keep a temporary user -> mail server
+# mapping. As long as user has simultaneous connections, the user is always
+# redirected to the same server. Each proxy server is running its own director
+# process, and the directors are communicating the state to each others.
+# Directors are mainly useful with NFS-like setups.
+
+# List of IPs or hostnames to all director servers, including ourself.
+# Ports can be specified as ip:port. The default port is the same as
+# what director service's inet_listener is using.
+#director_servers = 
+
+# List of IPs or hostnames to all backend mail servers. Ranges are allowed
+# too, like 10.0.0.10-10.0.0.30.
+#director_mail_servers = 
+
+# How long to redirect users to a specific server after it no longer has
+# any connections.
+#director_user_expire = 15 min
+
+# How the username is translated before being hashed. Useful values include
+# %Ln if user can log in with or without @domain, %Ld if mailboxes are shared
+# within domain.
+#director_username_hash = %Lu
+
+# To enable director service, uncomment the modes and assign a port.
+service director {
+  unix_listener login/director {
+    #mode = 0666
+  }
+  fifo_listener login/proxy-notify {
+    #mode = 0666
+  }
+  unix_listener director-userdb {
+    #mode = 0600
+  }
+  inet_listener {
+    #port = 
+  }
+}
+
+# Enable director for the wanted login services by telling them to
+# connect to director socket instead of the default login socket:
+service imap-login {
+  #executable = imap-login director
+}
+#service submission-login {
+#  #executable = submission-login director
+#}
+
+# Enable director for LMTP proxying:
+protocol lmtp {
+  #auth_socket_path = director-userdb
+}
diff --git a/dovecot/templates/conf.d/10-mail.conf.j2 b/dovecot/templates/conf.d/10-mail.conf.j2
index 52df2b7dba55a7ee7fdb07964632ae19a13e01b6..f74f8b76d1faf76f1613fa40702bca6a5d2ad148 100644
--- a/dovecot/templates/conf.d/10-mail.conf.j2
+++ b/dovecot/templates/conf.d/10-mail.conf.j2
@@ -79,6 +79,14 @@ namespace inbox {
   # See 15-mailboxes.conf for definitions of special mailboxes.
 }
 
+{% for namespace in dovecot_mail_namespaces %}
+namespace {
+  {% for key, value in namespace.items() %}
+  {{ key }} = {{ value }}
+  {% endfor %}
+}
+{% endfor %}
+
 # Example shared namespace configuration
 #namespace {
   #type = shared
diff --git a/dovecot/templates/conf.d/10-master.conf.j2 b/dovecot/templates/conf.d/10-master.conf.j2
index 3aabeeb42891fcf8c87e8a50c0e730b5605c7c60..14440ad8fed17ee236f4af6efafb7cba5920f27a 100644
--- a/dovecot/templates/conf.d/10-master.conf.j2
+++ b/dovecot/templates/conf.d/10-master.conf.j2
@@ -1,5 +1,5 @@
-#default_process_limit = 100
-#default_client_limit = 1000
+default_process_limit = {{ dovecot_process_limit }}
+default_client_limit = {{ dovecot_client_limit }}
 
 # Default VSZ (virtual memory size) limit for service processes. This is mainly
 # intended to catch and kill processes that leak memory before they eat up
@@ -15,9 +15,11 @@
 #default_internal_user = dovecot
 
 service imap-login {
+{% if not dovecot_disable_imap_starttls %}
   inet_listener imap {
     port = 143
   }
+{% endif %}
   inet_listener imaps {
     port = 993
     ssl = yes
@@ -42,10 +44,10 @@ service imap-login {
 #}
 
 service lmtp {
-   unix_listener /var/spool/postfix/private/dovecot-lmtp {
-	group = postfix
-	mode = 0600
-	user = postfix
+  unix_listener /var/spool/postfix/private/dovecot-lmtp {
+    mode = 0600
+    user = postfix
+    group = postfix
   }
 
   # Create inet listener only if you can't use the above UNIX socket
@@ -92,14 +94,26 @@ service auth {
 
   # Postfix smtp-auth
   unix_listener /var/spool/postfix/private/auth {
+{% if dovecot_postfix_public_private_partnership %}
     mode = 0666
+{% else %}
+    mode = 0660
+{% endif %}
+    user = postfix
+    group = postfix
   }
 
   # Auth process is run as this user.
-#  user = $default_internal_user
-   user = dovecot
-   group = dovecot
+  #user = $default_internal_user
+{% if dovecot_client_limit != 1000 %}
+  client_limit = {{ dovecot_client_limit * 2 }}
+{% endif %}
 }
+{% if dovecot_client_limit != 1000 %}
+service anvil {
+  client_limit = {{ dovecot_client_limit + 500 }}
+}
+{% endif %}
 
 service auth-worker {
   # Auth worker process is run as root by default, so that it can access
diff --git a/dovecot/templates/conf.d/15-lda.conf.j2 b/dovecot/templates/conf.d/15-lda.conf.j2
index 47e83ded6f4c9a62796ca70dcd849816342aa528..cdce6e3394deba423e0393702c7b449c4ebcb768 100644
--- a/dovecot/templates/conf.d/15-lda.conf.j2
+++ b/dovecot/templates/conf.d/15-lda.conf.j2
@@ -37,10 +37,10 @@
 #lda_original_recipient_header =
 
 # Should saving a mail to a nonexistent mailbox automatically create it?
-#lda_mailbox_autocreate = no
+lda_mailbox_autocreate = {{ 'yes' if dovecot_lda_mailbox_autocreate else 'no' }}
 
 # Should automatically created mailboxes be also automatically subscribed?
-#lda_mailbox_autosubscribe = no
+lda_mailbox_autosubscribe = {{ 'yes' if dovecot_lda_mailbox_autosubscribe else 'no' }}
 
 protocol lda {
   # Space separated list of plugins to load (default is global mail_plugins).
diff --git a/dovecot/templates/conf.d/15-mailboxes.conf.j2 b/dovecot/templates/conf.d/15-mailboxes.conf.j2
new file mode 100644
index 0000000000000000000000000000000000000000..08335585d9546200e80d8d70c2655326ca952bd7
--- /dev/null
+++ b/dovecot/templates/conf.d/15-mailboxes.conf.j2
@@ -0,0 +1,90 @@
+##
+## Mailbox definitions
+##
+
+# Each mailbox is specified in a separate mailbox section. The section name
+# specifies the mailbox name. If it has spaces, you can put the name
+# "in quotes". These sections can contain the following mailbox settings:
+#
+# auto:
+#   Indicates whether the mailbox with this name is automatically created
+#   implicitly when it is first accessed. The user can also be automatically
+#   subscribed to the mailbox after creation. The following values are
+#   defined for this setting:
+# 
+#     no        - Never created automatically.
+#     create    - Automatically created, but no automatic subscription.
+#     subscribe - Automatically created and subscribed.
+#  
+# special_use:
+#   A space-separated list of SPECIAL-USE flags (RFC 6154) to use for the
+#   mailbox. There are no validity checks, so you could specify anything
+#   you want in here, but it's not a good idea to use flags other than the
+#   standard ones specified in the RFC:
+#
+#     \All      - This (virtual) mailbox presents all messages in the
+#                 user's message store. 
+#     \Archive  - This mailbox is used to archive messages.
+#     \Drafts   - This mailbox is used to hold draft messages.
+#     \Flagged  - This (virtual) mailbox presents all messages in the
+#                 user's message store marked with the IMAP \Flagged flag.
+#     \Junk     - This mailbox is where messages deemed to be junk mail
+#                 are held.
+#     \Sent     - This mailbox is used to hold copies of messages that
+#                 have been sent.
+#     \Trash    - This mailbox is used to hold messages that have been
+#                 deleted.
+#
+# comment:
+#   Defines a default comment or note associated with the mailbox. This
+#   value is accessible through the IMAP METADATA mailbox entries
+#   "/shared/comment" and "/private/comment". Users with sufficient
+#   privileges can override the default value for entries with a custom
+#   value.
+
+# NOTE: Assumes "namespace inbox" has been defined in 10-mail.conf.
+namespace inbox {
+  # These mailboxes are widely used and could perhaps be created automatically:
+  mailbox Drafts {
+    special_use = \Drafts
+{% if dovecot_special_mailbox_auto_subscribe %}
+    auto = subscribe
+{% endif %}
+  }
+  mailbox {{ dovecot_spam_folder }} {
+    special_use = \Junk
+{% if dovecot_special_mailbox_auto_subscribe %}
+    auto = subscribe
+{% endif %}
+  }
+  mailbox Trash {
+    special_use = \Trash
+{% if dovecot_special_mailbox_auto_subscribe %}
+    auto = subscribe
+{% endif %}
+  }
+
+  # For \Sent mailboxes there are two widely used names. We'll mark both of
+  # them as \Sent. User typically deletes one of them if duplicates are created.
+  mailbox Sent {
+    special_use = \Sent
+{% if dovecot_special_mailbox_auto_subscribe %}
+    auto = subscribe
+{% endif %}
+  }
+  mailbox "Sent Messages" {
+    special_use = \Sent
+  }
+
+  # If you have a virtual "All messages" mailbox:
+  #mailbox virtual/All {
+  #  special_use = \All
+  #  comment = All my messages
+  #}
+
+  # If you have a virtual "Flagged" mailbox:
+  #mailbox virtual/Flagged {
+  #  special_use = \Flagged
+  #  comment = All my flagged messages
+  #}
+}
diff --git a/dovecot/templates/conf.d/20-imap.conf.j2 b/dovecot/templates/conf.d/20-imap.conf.j2
index a3ddfe4603f45e5bb665fc65ffacdf3f54259500..77cf9b45cf3439ea89fb259efe9808aff36e6058 100644
--- a/dovecot/templates/conf.d/20-imap.conf.j2
+++ b/dovecot/templates/conf.d/20-imap.conf.j2
@@ -39,8 +39,7 @@
 
 # How long to wait between "OK Still here" notifications when client is
 # IDLEing.
-#imap_idle_notify_interval = 2 mins
-imap_idle_notify_interval = 29 mins
+imap_idle_notify_interval = {{ dovecot_imap_idle_interval }}
 
 # ID field names and values to send to clients. Using * as the value makes
 # Dovecot use the default value. The following fields have default values
@@ -92,12 +91,11 @@ imap_idle_notify_interval = 29 mins
 
 protocol imap {
   # Space separated list of plugins to load (default is global mail_plugins).
-  #mail_plugins = $mail_plugins
+  mail_plugins = $mail_plugins
 
   # Maximum number of IMAP connections allowed for a user from each IP address.
   # NOTE: The username is compared case-sensitively.
-  #mail_max_userip_connections = 10
-  mail_max_userip_connections = 40
+  mail_max_userip_connections = {{ dovecot_imap_max_userip_connections }}
 }
 
 {% if dovecot_content_filter %}
diff --git a/dovecot/templates/conf.d/90-sieve.conf.j2 b/dovecot/templates/conf.d/90-sieve.conf.j2
index e5adf6845795fc0920dbe12e00870eaf3459612d..deba2ba68d04afae2896759ff6d8b9672bdc5322 100644
--- a/dovecot/templates/conf.d/90-sieve.conf.j2
+++ b/dovecot/templates/conf.d/90-sieve.conf.j2
@@ -36,7 +36,7 @@ plugin {
   # active script symlink is located.
   # For other types: use the ';name=' parameter to specify the name of the
   # default/active script.
-  sieve = file:~/sieve;active=~/.dovecot.sieve
+  sieve = {{ dovecot_sieve }}
 
   # The default Sieve script when the user has none. This is the location of a
   # global sieve script file, which gets executed ONLY if user's personal Sieve
diff --git a/dovecot/templates/conf.d/auth-system.conf.ext.j2 b/dovecot/templates/conf.d/auth-system.conf.ext.j2
new file mode 100644
index 0000000000000000000000000000000000000000..dadb9f7c9734f03d8a6b149afbb7a51213ee0f6c
--- /dev/null
+++ b/dovecot/templates/conf.d/auth-system.conf.ext.j2
@@ -0,0 +1,74 @@
+# Authentication for system users. Included from 10-auth.conf.
+#
+# <doc/wiki/PasswordDatabase.txt>
+# <doc/wiki/UserDatabase.txt>
+
+# PAM authentication. Preferred nowadays by most systems.
+# PAM is typically used with either userdb passwd or userdb static.
+# REMEMBER: You'll need /etc/pam.d/dovecot file created for PAM
+# authentication to actually work. <doc/wiki/PasswordDatabase.PAM.txt>
+passdb {
+  driver = pam
+  # [session=yes] [setcred=yes] [failure_show_msg=yes] [max_requests=<n>]
+  # [cache_key=<key>] [<service name>]
+  #args = dovecot
+}
+
+# System users (NSS, /etc/passwd, or similar).
+# In many systems nowadays this uses Name Service Switch, which is
+# configured in /etc/nsswitch.conf. <doc/wiki/AuthDatabase.Passwd.txt>
+#passdb {
+  #driver = passwd
+  # [blocking=no]
+  #args = 
+#}
+
+# Shadow passwords for system users (NSS, /etc/shadow or similar).
+# Deprecated by PAM nowadays.
+# <doc/wiki/PasswordDatabase.Shadow.txt>
+#passdb {
+  #driver = shadow
+  # [blocking=no]
+  #args = 
+#}
+
+# PAM-like authentication for OpenBSD.
+# <doc/wiki/PasswordDatabase.BSDAuth.txt>
+#passdb {
+  #driver = bsdauth
+  # [blocking=no] [cache_key=<key>]
+  #args =
+#}
+
+##
+## User databases
+##
+
+# System users (NSS, /etc/passwd, or similar). In many systems nowadays this
+# uses Name Service Switch, which is configured in /etc/nsswitch.conf.
+userdb {
+  # <doc/wiki/AuthDatabase.Passwd.txt>
+  driver = passwd
+  # [blocking=no]
+  #args = 
+
+  # Override fields from passwd
+  #override_fields = home=/home/virtual/%u
+}
+
+# Static settings generated from template <doc/wiki/UserDatabase.Static.txt>
+#userdb {
+  #driver = static
+  # Can return anything a userdb could normally return. For example:
+  #
+  #  args = uid=500 gid=500 home=/var/mail/%u
+  #
+  # LDA and LMTP needs to look up users only from the userdb. This of course
+  # doesn't work with static userdb because there is no list of users.
+  # Normally static userdb handles this by doing a passdb lookup. This works
+  # with most passdbs, with PAM being the most notable exception. If you do
+  # the user verification another way, you can add allow_all_users=yes to
+  # the args in which case the passdb lookup is skipped.
+  #
+  #args =
+#}
diff --git a/postfix/defaults/main.yml b/postfix/defaults/main.yml
index 3c1adc3d4abd2be75b60b8d69a61a57f29f645af..90d9f6345f7552c53f0d459ebda09a6ecca5987d 100644
--- a/postfix/defaults/main.yml
+++ b/postfix/defaults/main.yml
@@ -3,6 +3,7 @@
 postfix_domains:
   - "{{ domain }}"
 postfix_virtual_domains: []
+postfix_mailname: "{{ domain }}"
 
 postfix_tls_cert: /etc/ssl/private/fullchain.pem
 postfix_tls_key: /etc/ssl/private/privkey.pem
@@ -16,6 +17,24 @@ postfix_enable_dovecot: true
 postfix_enable_submission: true
 postfix_enable_smtps: false
 
+postfix_sasl_auth_header: false
+postfix_enable_long_queue_ids: false
+postfix_tls_received_header: false
+
+# These variables were introduced for compatibility to a certain setup.
+# They may disappear without prior notice and/or may not work as expected.
+postfix_smtpd_recipient_limit: 1000
+postfix_minimal_backoff_time: 300s
+postfix_maximal_backoff_time: 4000s
+postfix_mailbox_command: '/usr/lib/dovecot/dovecot-lda -f "$SENDER" -a "$RECIPIENT"'
+postfix_relay_domains: []
+postfix_alias_maps:
+  - cdb:/etc/aliases
+postfix_virtual_alias_maps:
+  - cdb:/etc/postfix/virtual
+postfix_sender_login_maps:
+  - proxy:pcre:/etc/postfix/login_maps.pcre
+
 postfix_enable_postscreen: true
 postfix_enable_memcached: false
 postfix_login_suffix: ''
@@ -34,6 +53,7 @@ postfix_network_access:
 postfix_content_filter: false  # or: spamassassin
 postfix_message_size_limit: 10240000  # 10M
 
+postfix_aliases_rt_url: ''
 postfix_aliases_rt: []
 #  - queue: IT
 #    url: https://rt.example.com
diff --git a/postfix/tasks/main.yml b/postfix/tasks/main.yml
index 9af48035e6fd391149cb3daf66876b455d0923a0..53527ce364d1794db446ca080e27afd5357e9e27 100644
--- a/postfix/tasks/main.yml
+++ b/postfix/tasks/main.yml
@@ -32,10 +32,35 @@
     src: "{{ item }}.j2"
     dest: "/etc/postfix/{{ item }}"
   with_items:
-    - login_maps.pcre
     - master.cf
     - main.cf
-    - postscreen_access.cidr
+  notify:
+    - restart postfix
+  tags:
+    - postfix
+    - mail
+
+- name: ensure login maps list is present
+  template:
+    src: "login_maps.pcre.j2"
+    dest: "/etc/postfix/login_maps.pcre"
+  when:
+    - not postfix_satellite_only
+    - postfix_enable_dovecot
+    - not postfix_fsmpi|default(false)
+  notify:
+    - restart postfix
+  tags:
+    - postfix
+    - mail
+
+- name: ensure postscreen access list is present
+  template:
+    src: "postscreen_access.cidr.j2"
+    dest: "/etc/postfix/postscreen_access.cidr"
+  when:
+    - not postfix_satellite_only
+    - postfix_enable_postscreen
   notify:
     - restart postfix
   tags:
@@ -105,7 +130,7 @@
   template:
     src: virtual.j2
     dest: /etc/postfix/virtual
-  when: virtual_aliases is defined or postfix_virtual_domains|count > 0
+  when: virtual_aliases|default([])|count > 0 or postfix_virtual_domains|count > 0
   notify:
     - postmap virtual
   tags:
diff --git a/postfix/templates/aliases.j2 b/postfix/templates/aliases.j2
index 1604e7c47ae81a55c295c82ef8db2577d1bf9ed9..ea3de678a86d9c971b7e9b2e961b15dfb1c3eb76 100644
--- a/postfix/templates/aliases.j2
+++ b/postfix/templates/aliases.j2
@@ -1,7 +1,14 @@
-{% for alias in system_aliases %}
-{{ alias.src }}: {{ alias.dest }}
+{% for alias in system_aliases|default([]) %}
+{% if alias.src is string %}
+{{ alias.src }}: {{ alias.dest if alias.dest is string else alias.dest|join(', ') }}
+{% else %}
+{% for src in alias.src %}
+{{ src }}: {{ alias.dest if alias.dest is string else alias.dest|join(', ') }}
 {% endfor %}
+{% endif %}
+{% endfor %}
+
 {% for alias in postfix_aliases_rt|default([]) %}
-{{ alias.address|default(alias.queue|lower) }}: "|/usr/bin/rt-mailgate --queue {{ alias.queue }} --action correspond --url {{ alias.url }}"
-{{ alias.address|default(alias.queue|lower) }}-comment: "|/usr/bin/rt-mailgate --queue {{ alias.queue }} --action comment --url {{ alias.url }}"
+{{ alias.address|default(alias.queue|lower) }}: "|/usr/bin/rt-mailgate --queue {{ alias.queue }} --action correspond --url {{ alias.url|default(postfix_aliases_rt_url) }}"
+{{ alias.address|default(alias.queue|lower) }}-comment: "|/usr/bin/rt-mailgate --queue {{ alias.queue }} --action comment --url {{ alias.url|default(postfix_aliases_rt_url) }}"
 {% endfor %}
diff --git a/postfix/templates/mailname.j2 b/postfix/templates/mailname.j2
index 81008bac28684edb06528802426d0c82acdeb96d..422f887bd470508d9d44c5137ccd5a76c9100ce7 100644
--- a/postfix/templates/mailname.j2
+++ b/postfix/templates/mailname.j2
@@ -1 +1 @@
-{{ domain }}
+{{ postfix_mailname }}
diff --git a/postfix/templates/main.cf.j2 b/postfix/templates/main.cf.j2
index 988b60a64dfecee8b7ae4926c29fd09fb1f1d1aa..5d9800c17bde4f85702c18086e337a1438e34e53 100644
--- a/postfix/templates/main.cf.j2
+++ b/postfix/templates/main.cf.j2
@@ -1,14 +1,18 @@
 # See /usr/share/postfix/main.cf.dist for a commented, more complete version
 
 inet_interfaces = {{ "loopback-only" if postfix_satellite_only else "all" }}
-inet_protocols = all
+inet_protocols = {{ "all" if not postfix_fsmpi|default(false) else "ipv4" }}
 myhostname = {{ ansible_fqdn }}
 myorigin = /etc/mailname
 mydestination = $myhostname localhost {{ postfix_domains | join(" ") }}
 mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 {{ postfix_my_networks|join(" ") }}
+
+relay_domains = {{ postfix_relay_domains|join(" ") }}
 relayhost = {{ postfix_relay_host }}
 {% if postfix_transport_maps|count > 0 %}
 transport_maps = cdb:/etc/postfix/transport
+{% elif postfix_fsmpi|default(false) and ansible_hostname == "mail" %}
+transport_maps = pgsql:/etc/postfix/pgsql-transport.cf
 {% endif %}
 {% if postfix_luser_relay != "" %}
 luser_relay = {{ postfix_luser_relay }}
@@ -16,37 +20,38 @@ local_recipient_maps =
 {% endif %}
 
 {% if not postfix_satellite_only and postfix_enable_dovecot %}
-{% if postfix_domains|count > 0 %}
-{% if postfix_prefer_lmtp %}
+{% if postfix_domains|count > 0 and postfix_prefer_lmtp %}
 mailbox_transport = lmtp:unix:private/dovecot-lmtp
-{% else %}
-mailbox_command = /usr/lib/dovecot/dovecot-lda -f "$SENDER" -a "$RECIPIENT"
-{% endif %}
+{% elif postfix_domains|count > 0 and not postfix_prefer_lmtp %}
+mailbox_command = {{ postfix_mailbox_command }}
 {% endif %}
 
-smtpd_sender_login_maps = proxy:pcre:/etc/postfix/login_maps.pcre
+smtpd_sender_login_maps = {{ postfix_sender_login_maps|join(" ") }}
+smtpd_sender_restrictions = reject_sender_login_mismatch
+
 smtpd_sasl_type = dovecot
 smtpd_sasl_path = private/auth
 smtpd_sasl_auth_enable = yes
+smtpd_sasl_security_options = noanonymous
+smtpd_sasl_authenticated_header = {{ 'yes' if postfix_sasl_auth_header else 'no' }}
+smtpd_sasl_local_domain = $myhostname
 {% endif %}
 
-append_dot_mydomain = no
 biff = no
-compatibility_level = 2
-#delay_warning_time = 4h
+append_dot_mydomain = no
+readme_directory = no
 disable_vrfy_command = yes
-#enable_long_queue_ids = yes
-mailbox_size_limit = 0
+compatibility_level = 2
+
+enable_long_queue_ids = {{ 'yes' if postfix_enable_long_queue_ids else 'no' }}
+minimal_backoff_time = {{ postfix_minimal_backoff_time }}
+maximal_backoff_time = {{ postfix_maximal_backoff_time }}
 message_size_limit = {{ postfix_message_size_limit }}
-readme_directory = no
+mailbox_size_limit = 0
 recipient_delimiter = +
-#strict_rfc821_envelopes = no
 
 smtpd_banner = $myhostname ESMTP $mail_name
-smtpd_relay_restrictions =
-	permit_mynetworks
-	permit_sasl_authenticated
-	defer_unauth_destination
+smtpd_recipient_limit = {{ postfix_smtpd_recipient_limit }}
 {% if postfix_verify_spf %}
 smtpd_recipient_restrictions=
      permit_mynetworks
@@ -65,6 +70,7 @@ smtp_tls_security_level = may
 smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
 smtpd_tls_security_level = may
 smtpd_tls_auth_only = yes
+smtpd_tls_received_header = {{ 'yes' if postfix_tls_received_header else 'no' }}
 smtpd_tls_cert_file = {{ postfix_tls_cert }}
 smtpd_tls_key_file = {{ postfix_tls_key }}
 smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
@@ -96,10 +102,10 @@ smtpd_tls_dh1024_param_file = /etc/postfix/dh.pem
 tls_ssl_options = NO_COMPRESSION
 {% endif %}
 
-alias_maps = cdb:/etc/aliases
+alias_maps = {{ postfix_alias_maps|join(" ") }}
 alias_database = cdb:/etc/aliases
-{% if virtual_aliases is defined or postfix_virtual_domains|count > 0 %}
-virtual_alias_maps = cdb:/etc/postfix/virtual
+{% if virtual_aliases|default([])|count > 0 or postfix_virtual_alias_maps != ['cdb:/etc/postfix/virtual'] %}
+virtual_alias_maps = {{ postfix_virtual_alias_maps|join(" ") }}
 {% endif %}
 
 {% if postfix_virtual_domains|count > 0 and postfix_enable_dovecot %}
@@ -114,6 +120,18 @@ virtual_gid_maps = static:5000
 {% set _x = postfix_notify_classes.extend(["resource", "software"]) %}
 notify_classes = {{ postfix_notify_classes|unique|join(", ") }}
 
+{% if postfix_fsmpi|default(false) and ansible_hostname == "lists" %}
+mailman_destination_recipient_limit = 1
+{% elif postfix_fsmpi|default(false) and ansible_hostname == "mail" %}
+local_header_rewrite_clients = permit_mynetworks
+2525_smtpd_recipient_restrictions = check_sender_access
+	pcre:/etc/postfix/nullmailer_class.pcre
+smtpd_restriction_classes = nullmailer
+nullmailer =
+	check_recipient_access cdb:/etc/postfix/known_mailaddresses
+	check_recipient_access pcre:/etc/postfix/nullmailer_recipient_filters.pcre
+{% endif %}
+
 {% if postfix_enable_postscreen and not postfix_satellite_only %}
 postscreen_access_list = permit_mynetworks
                          cidr:/etc/postfix/postscreen_access.cidr
diff --git a/postfix/templates/master.cf.j2 b/postfix/templates/master.cf.j2
index 7d27464edfd76adc523c0f2d1fefd2cb13f35420..87d6bb458815e3976ee66a9fc211f94a9b5505e3 100644
--- a/postfix/templates/master.cf.j2
+++ b/postfix/templates/master.cf.j2
@@ -9,50 +9,54 @@
 #               (yes)   (yes)   (no)    (never) (100)
 # ==========================================================================
 
-{% if postfix_enable_postscreen and not postfix_satellite_only %}
-smtp      inet  n       -       y       -       1       postscreen
-{% else %}
+{% if postfix_satellite_only %}
 smtp     inet  n       -       y       -       -       smtpd
 {% endif %}
 {% if not postfix_satellite_only %}
+{% if postfix_enable_postscreen %}
+smtp      inet  n       -       y       -       1       postscreen
 smtpd     pass  -       -       y       -       -       smtpd
 {% if postfix_content_filter %}
   -o content_filter={{ postfix_content_filter }}
 {% endif %}
 dnsblog   unix  -       -       y       -       0       dnsblog
 tlsproxy  unix  -       -       y       -       0       tlsproxy
+{% else %}
+smtp     inet  n       -       y       -       -       smtpd
+{% endif %}
 {% if postfix_enable_submission %}
 submission inet n       -       y       -       -       smtpd
-  -o smtpd_sasl_security_options=noanonymous
-  -o smtpd_sasl_local_domain=$myhostname
-  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
-  -o smtpd_sender_restrictions=reject_sender_login_mismatch
-  -o smtpd_recipient_restrictions=reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject
   -o syslog_name=postfix/submission
+  -o milter_macro_daemon_name=ORIGINATING
+  -o smtpd_tls_security_level=encrypt
+  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
 {% if postfix_content_filter %}
   -o content_filter={{ postfix_content_filter }}
 {% endif %}
-#  -o smtpd_tls_security_level=encrypt
-#  -o smtpd_sasl_auth_enable=yes
-#  -o smtpd_reject_unlisted_recipient=no
-#  -o smtpd_client_restrictions=$mua_client_restrictions
-#  -o smtpd_helo_restrictions=$mua_helo_restrictions
-#  -o smtpd_sender_restrictions=$mua_sender_restrictions
-#  -o smtpd_recipient_restrictions=
-#  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
-#  -o milter_macro_daemon_name=ORIGINATING
 {% endif %}
 {% if postfix_enable_smtps %}
 smtps     inet  n       -       y       -       -       smtpd
   -o syslog_name=postfix/smtps
-  -o smtpd_tls_wrappermode=yes
-  -o smtpd_sasl_auth_enable=yes
-  -o smtpd_reject_unlisted_recipient=no
-  -o smtpd_recipient_restrictions=
-  -o smtpd_relay_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
   -o milter_macro_daemon_name=ORIGINATING
+  -o smtpd_tls_wrappermode=yes
+  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
+{% if postfix_content_filter %}
+  -o content_filter={{ postfix_content_filter }}
+{% endif %}
 {% endif %}
 #628	  inet  n       -       y       -       -       qmqpd
+{% if postfix_fsmpi|default(false) and ansible_hostname == "mail" %}
+2525       inet  n       -       y       -       -       smtpd
+  -o syslog_name=postfix/smtps-internal
+  -o milter_macro_daemon_name=ORIGINATING
+  -o smtpd_tls_wrappermode=yes
+  -o smtpd_sasl_auth_enable=no
+  -o smtpd_sender_login_maps=
+  -o smtpd_client_restrictions=permit_mynetworks,reject
+  -o smtpd_recipient_restrictions=$2525_smtpd_recipient_restrictions
+  -o virtual_alias_domains=fsmpi.rwth-aachen.de
+  -o virtual_alias_maps=cdb:/etc/postfix/nullmailer_alias
+{% endif %}
 {% endif %}
 pickup    unix  n       -       y       60      1       pickup
 cleanup   unix  n       -       y       -       0       cleanup
@@ -69,7 +73,11 @@ proxymap  unix  -       -       n       -       -       proxymap
 proxywrite unix -       -       n       -       1       proxymap
 smtp      unix  -       -       y       -       -       smtp
 relay     unix  -       -       y       -       -       smtp
-#       -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
+{% if postfix_fsmpi|default(false) and ansible_hostname == "mail" %}
+  -o smtp_fallback_relay=
+{% else %}
+#  -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
+{% endif %}
 showq     unix  n       -       y       -       -       showq
 error     unix  -       -       y       -       -       error
 retry     unix  -       -       y       -       -       error
@@ -92,9 +100,6 @@ postlog   unix-dgram n  -       n       -       1       postlogd
 # and other message envelope options.
 # ====================================================================
 
-# maildrop. See the Postfix MAILDROP_README file for details.
-# Also specify in main.cf: maildrop_destination_recipient_limit=1
-
 {% if postfix_verify_spf %}
 policy-spf unix -       n       n       -       0       spawn
   user=nobody argv=/usr/bin/policyd-spf
@@ -102,24 +107,20 @@ policy-spf unix -       n       n       -       0       spawn
 
 {% if not postfix_satellite_only and postfix_enable_dovecot %}
 dovecot   unix  -       n       n       -       -       pipe
+{% if postfix_fsmpi|default(false) %}
+	flags=DRhu argv=/usr/lib/dovecot/deliver -d ${recipient}
+{% else %}
   flags=DRhu user=5001:5000 argv=/usr/lib/dovecot/dovecot-lda -f ${sender} -a ${original_recipient} -d ${user}@${nexthop}
+{% endif %}
+{% endif %}
 
 {% if postfix_content_filter == 'spamassassin' %}
 spamassassin	unix -     n       n       -       -       pipe
   user=debian-spamd argv=/usr/bin/spamc -f -e /usr/sbin/sendmail -oi -f ${sender} ${recipient}
 {% endif %}
-{% endif %}
 
-#maildrop  unix  -       n       n       -       -       pipe
-#  flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
-#uucp      unix  -       n       n       -       -       pipe
-#  flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
-#ifmail    unix  -       n       n       -       -       pipe
-#  flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
-#bsmtp     unix  -       n       n       -       -       pipe
-#  flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient
-#scalemail-backend unix	-	n	n	-	2	pipe
-#  flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}
-#mailman   unix  -       n       n       -       -       pipe
-#  flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
-#  ${nexthop} ${user}
+{% if postfix_fsmpi|default(false) and ansible_hostname == "lists" %}
+mailman   unix  -       n       n       -       -       pipe
+  flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
+  ${nexthop} ${user}
+{% endif %}
diff --git a/postfix/templates/virtual.j2 b/postfix/templates/virtual.j2
index ac13c8d3bf8f2f6227a9facadc323779b642f573..99d4e929cf1121c02a9a11a02211efe499c01448 100644
--- a/postfix/templates/virtual.j2
+++ b/postfix/templates/virtual.j2
@@ -4,9 +4,9 @@ hostmaster@{{ domain }} {{ adminaddr }}
 abuse@{{ domain }} {{ adminaddr }}
 {% endfor %}
 
-{% for alias in virtual_aliases %}
+{% for alias in virtual_aliases|default([]) %}
 {% if alias.src is string %}
-{{ alias.src }} {{ alias.dest }}
+{{ alias.src }} {{ alias.dest if alias.dest is string else alias.dest|join(', ') }}
 {% else %}
 {% for src in alias.src %}
 {{ src }}@{{ alias.domain }} {{ alias.dest if alias.dest is string else alias.dest|join(', ') }}