Mail delivery configuration with LDAP

Last time I wrote about users’ authentication in LDAP directory to allow them receiving and sending e-mails. Now is time to configure Postfix for mail delivery to appropriate mailboxes.
If you compile Postfix themselves, you need to remember to add support for LDAP. My description is based on Ubuntu, so I only need to install postfix-ldap package:

$ sudo -i
# apt-get install postfix-ldap

This will add support for ldap: maps in Postfix.

Now we go to Postfix configuration:

# cd /etc/postfix
# vi main.cf

In main.cf we need to add something like this (you need to replace example.com with your domain name):

ldap_bind_dn = cn=admin,dc=example,dc=com
ldap_bind_pw = secret
ldap_search_base = o=hosting,dc=example,dc=com
ldap_domain = dc=example,dc=com
ldap_server_host = localhost
ldap_server_port = 389
ldap_version = 3

# Accounts
accounts_server_host = $ldap_server_host
accounts_search_base = $ldap_search_base
accounts_query_filter = (&(objectClass=mailUser)(mail=%s))
accounts_result_attribute = mailMessageStore
accounts_cache = no
accounts_bind = yes
accounts_bind_dn = $ldap_bind_dn
accounts_bind_pw = $ldap_bind_pw
accounts_version = $ldap_version

accountsmap_server_host = $ldap_server_host
accountsmap_search_base = $ldap_search_base
accountsmap_query_filter = (&(objectClass=mailUser)(mail=%s))
accountsmap_result_attribute = mail
accountsmap_cache = no
accountsmap_bind = yes
accountsmap_bind_dn = $ldap_bind_dn
accountsmap_bind_pw = $ldap_bind_pw
accountsmap_version = $ldap_version

# aliases
aliases_server_host = $ldap_server_host
aliases_search_base = $ldap_search_base
aliases_query_filter = (&(objectClass=mailAlias)(mail=%s))
aliases_result_attribute = mailForwardingAddress
aliases_bind = yes
aliases_cache = no
aliases_bind_dn = $ldap_bind_dn
aliases_bind_pw = $ldap_bind_pw
aliases_version = $ldap_version

# transports
transport_server_host = $ldap_server_host
transport_search_base = $ldap_search_base
transport_query_filter = (&(objectClass=mailDomain)(domainName=%s))
transport_result_attribute = mtaTransport
transport_cache = no
transport_bind = yes
transport_scope = one
transport_bind_dn = $ldap_bind_dn
transport_bind_pw = $ldap_bind_pw
transport_version = $ldap_version

# transport_maps
maildrop_destination_concurrency_limit = 2
maildrop_destination_recipient_limit = 1
transport_maps = ldap:transport
virtual_alias_maps = ldap:aliases, ldap:accountsmap

# virtual accounts for delivery
virtual_mailbox_domains = ldap:transport
virtual_mailbox_base = /vdhome
virtual_mailbox_maps = ldap:accounts
virtual_minimum_uid = 501
virtual_uid_maps = static:501
virtual_gid_maps = static:501

local_recipient_maps = $alias_maps $virtual_mailbox_maps

The lines above should be enough for mail delivery. I tried to simplify this, so I do not chceck account status (active/nonactive) etc. There is no need to configure cn=admin to read directory also (security), you should define another user for this purpose, but it will be sufficient for now.

Now we need to restart Postfix and check logs for errors. If Postfix is running, we can leave it and go to mail configuration in LDAP directory. You can use description from Mail system authentication in LDAP, but I will add new domain virtdomain.com, user jsmith and alias postmaster, which will point to jsmith. You can create this in phpLDAPadmin or another utility, or you can import LDIF like this:

dn: domainName=virtdomain.com,o=hosting,dc=example,dc=com
domainname: virtdomain.com
mtatransport: virtual
objectclass: mailDomain
objectclass: top

dn: uid=jsmith,domainName=virtdomain.com,o=hosting,dc=example,dc=com
cn: John Smith
givenname: John
homedirectory: /vdhome/virtdomain.com/jsmith
mail: jsmith@virtdomain.com
mailmessagestore: virtdomain.com/jsmith/Maildir/
objectclass: inetOrgPerson
objectclass: top
objectclass: mailUser
sn: Smith
uid: jsmith
userpassword: {MD5}XD9034sf8w83sfoXXg==

dn: mail=postmaster@virtdomain.com,domainName=virtdomain.com,o=hosting,dc=example,
 dc=com
cn: Postmaster
mail: postmaster@virtdomain.com
mailforwardingaddress: jsmith@virtdomain.com
objectclass: mailAlias
objectclass: top

If you add this with phpLDAPadmin, then you need to choose inetOrgPerson as structural objectClass, and then add mailUser object Class and needed attributes. As RDN you can choose mail attribute, so you do not need to add uid then.

Please note homeDirectory and mailMessageStore attributes. The last one contains relative path to user’s mailbox. Base directory is added by Postfix, which gets it from virtual_mailbox_base variable. Dovecot in contrast uses homeDirectory attribute and stick /Maildir on the end. This is not good situation, and later I will write how to eliminate it. But it should work for now.

Let’s check if postfix resolves LDAP maps properly:

# postmap -q "virtdomain.com" ldap:transport
virtual
# postmap -q "postmaster@virtdomain.com" ldap:aliases
jsmith@virtdomain.com
# postmap -q "jsmith@virtdomain.com" ldap:accounts
virtdomain.com/jsmith/Maildir/
# postmap -q "jsmith@virtdomain.com" ldap:accountsmap
jsmith@virtdomain.com

You should see something like this above. If you do not have any results or you have connection to LDAP error, then you should check logs and improve configuration.

If everything is fine, you can send message to yourself, and it should be delivered to mailbox. If you see in logs message like this:

status=bounced (mail for example.com loops back to myself)

then there is a problem with transport. Note: you will find many results and solutions for this problem, but many of them suggest that you should your domain (example.com) to mydestination, this is not good solution! In Postfix documentation, section VIRTUAL_README Vietse wrote:

NEVER list a virtual MAILBOX domain name as a mydestination domain!
NEVER list a virtual MAILBOX domain name as a virtual ALIAS domain!

in the other words: if domain is virtual, then should be virtual, Postfix will receive mail for this domain, you need only point him where to deliver.

You may also like...

Leave a Reply