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.
