ldap, postfix and courier-imap howto

Author: J.Vriesman, joenix@gmx.net

All new documentation (including new versions of this one) will be put here.



This document describes the setup of an ldap based mailsystem, using openldap, postfix and courier-imap. It was tested on Linux, but it should work on any os if postfix, openldap and courier-imap are available.


1 The ldap server

1.1 About the ldap server setup

The ldap server contains all information needed by the smtp and imap server and can also be used as an address book. Since there seemed to be no objectclass which is exactly fit for this purpose, some attributes are used in a setup-specific way, e.g. ''seeAlso'' for shared folders.

1.2 Schema's

The following schema's are included in slapd.conf:

Not all schema's are used.

1.3 The tree

Two leaves of the ldap tree are essential for the imap and smtp servers, the first one stores ''system'' information, the other one ''account'' information.

The base for the system leave can be:

Under this system leave there is a leave ''ou=postfix'', under which the accepted domains are stored. From here and further this is refered to as the ''system-leave''.

The base for the accounts can be:

Under the account tree the user information is stored, including addresses, passwords, aliases and shared folders. From here and further this is refered to as the ''account-leave''.

1.4 System-leave

Under ''ou=postfix,system leave'' there is an entry for every top-level domain needed by the smtp server, eg:





The attributes of these entry's define the accepted domains for the smtp server using attribute type ''associatedDomain''. Two objectclasses are needed:

An example ldif file to make the smtp server accept mail for testdomain.nu, anotherdomain.nu and mydomain.nl:


dn: ou=System, o=company
userPassword:: encrypted password
ou: system
objectClass: organizationalUnit

dn: ou=postfix, ou=system, o=company
ou: postfix
objectClass: organizationalUnit

dn: dc=nl,ou=postfix, ou=system, o=company
associatedDomain: mydomain.nl
dc: nl
objectClass: dNSDomain
objectClass: domainRelatedObject

dn: dc=nu,ou=postfix, ou=system, o=company
associatedDomain: testdomain.nu
associatedDomain: anotherdomain.nu
dc: nu
objectClass: dNSDomain
objectClass: domainRelatedObject

Note that the hostname of any of the smtpservers is not mentioned, neither is the name ''localhost'', these names will be accepted, but they are configured in the postfix configuration file.

The dn of the system leave has a ''userPassword'', system has read-only access to the ldap database and is used by the smtp and imap server to read from the ldap database.

1.5 Personal accounts

Under the account-leave all user accounts are entry's with a dn like:


dn: cn=Test User,account-leave

A personal account entry uses the following object classes:

There seem to be different versions of the qmail.schema file, make sure that in the qmail.schema file qmailUID and qmailGID have ''EQUALITY numericStringMatch'', mailMessageStore has ''EQUALITY caseExactIA5Match'', and all other EQUALITY's in qmail.schema are ''caseIgnoreIA5Match''.

The following subsubsections describe the attributes used by the imap and smtp server.

1.5.1 cn

This attribute must exists, it contains the full name of the used, e.g. ''Abert Onestone''.

1.5.2 uid

This attribute must exists, it can be any string and it's used as a login-id by the imap server.

1.5.3 userPassword

This attribute is used by the imap server to authenticate, it's encrypted.

1.5.4 ou

This is the ou part of the dn, for example, if you are using ou=Tokelau,o=company as your account-leave, the ou in every account is simply ''Tokelau''.

1.5.5 givenName

The given name, only used by the address book, not by the servers.

1.5.6 sn

The surname, only used by the address book, not by the servers.

1.5.7 mail

The main email address of the user, domain included, e.g. albert.onestone@anotherdomain.nu, make sure that the domain is listed in the system-leave, the mail attribute must exist

You can use the same email address in different accounts, it will deliver the mail to that address to multiple users.

IMPORTANT: Only use one mail attribute per account, use mailAlternateAddress for aliases!

1.5.8 mailAlternateAddress

This attribute is optional, and can be used multiple times, it contains the aliases, full email address aliases, just like the mail attribute, make sure that the domains you use are listed in the system-leave.

1.5.9 accountStatus

For every personal account the value of this attribute should be ''active'', if the value is ''inactive'' the smtp server will bounce all mail for this user with ''unknown user''.

1.5.10 seeAlso

This attribute is optional, it refers to another dn in the account-leave with accountStatus=shared, seeAlso can be used multiple times per account, when the script ''makeMailMessageStoreDirs'' is executed it creates the directories and links needed to access the shared folders.

1.5.11 mailMessageStore

This attribute must be present, it contains the full path to the maildir where all mail of the user is stored, make sure in ends with a ''/'', otherwise the smtp server doesn't deliver in maildir format, e.g. ''mailMessageStore: /vmail/harry.potter/Maildir/''.

1.6 Shared folders

Shared folders are exactly the same in the ldap server as the personal accounts, exept that it doesn't need a userPassword, and that accountStatus is ''shared''.

Since the entry fro the shared folder in the ldap database must have a uid, the uid entry is the name of the folder where mail for this account will be delivered to. A shared account has one extra attribute:

1.6.1 PostOfficeBox

This attribute can be used multiple times, they contain the names of the subfolders in the shared folder. Not the main folder where mail gets delivered, that one is stored in ''uid''. The actual directories wil be created when the script ''makeMailMessageStoreDirs'' is executed.

1.7 Example account ldif

The following ldif file represents two user accounts, ''Albert Onestone'' and ''Seven of Nine'', who are both using the shared folder ''Timetravel weekly''. The shared folder contains a folder incoming, past.editions and future.editions, and mail to timetravel@anotherdomain.nu is delivered to the incoming shared folder.

Example ldif:


dn: cn=Albert Onestone, ou=Tokelau, o=company
userPassword:: encrypted
givenName: Albert
sn: Onestone
mailMessageStore: /vmail/albert.onestone/Maildir/
mail: albert.onestone@anotherdomain.nu
mailAlternateAddress: a.onestone@anotherdomain.nu
mailAlternateAddress: ao@anotherdomain.nu
ou: Tokelau
uid: onestonea
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: qmailUser
accountStatus: active 
cn: Albert Onestone
seeAlso: cn=Timetravel weekly,ou=Tokelau,o=company

dn: cn=Seven of Nine, ou=Tokelau, o=company
userPassword:: encrypted
givenName: Seven
sn: Nine
mailMessageStore: /vmail/seven.of.nine/Maildir/
mail: seven.of.nine@anotherdomain.nu
mailAlternateAddress: s.o.9@anotherdomain.nu
ou: Tokelau
uid: nines
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: qmailUser
accountStatus: active
cn: Seven of Nine
seeAlso: cn=Timetravel weekly,ou=Tokelau,o=company

dn: cn=Timetravel weekly, ou=Tokelau, o=company
givenName: Timetravel
sn: weekly
mailMessageStore: /vmail/shared/timetravel.weekly/incoming/
mail: timetravel@anotherdomain.nu
ou: Tokelau
uid: incoming
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: qmailUser
accountStatus: shared
postOfficeBox: past.editions
postOfficeBox: future.editions

The mail system assumes that all mail is stored under one directory, in this case ''/vmail'', whenever a shared account is created, it's mailMessageStore must be under /mailbasedirectory/shared. Under the mailbasedirectory, two directories must be created for shared folders, one is called ''shared'', the other one is ''shared.maildirs'', both directories must be writable by the mail owner. The shared.maildirs directory is used by the imap server to access the messages, the shared directory is used by the smtp server, it contains symbolic links to the incoming folders of the shared folders.

1.8 makeMailMessageStoreDirs

This is a listing of a script makeMailMessageStoreDirs, which creates maildirs and shared folders out of the ldap data, it also creates the right links to shared folders from the seeAlso attributes.

IMPORTANT: the script must be executed with the uid and gid of the mail owner, if it's executed as root, the mailfolders will be unaccessable!

Listing of makeMailMessageStoreDirs:


systempass="your_system_password" # the userPassword of dn: system-leave
systemleave="system-leave" # e.g. ou=System,o=company
accountleave="account-leave" # e.g. ou=Tokelau,o=company

ldappersonaldirs=`ldapsearch -x -w $systempass -D "$systemleave" -b "$accountleave" "(accountStatus=active)" mailMessageStore | grep "^[^#]" | grep mailMessageStore | awk '{ print $2 }'`
ldapshareddirs=`ldapsearch -x -w $systempass -D "$systemleave" -b "$accountleave" "(accountStatus=shared)" mailMessageStore | grep "^[^#]" | grep mailMessageStore | awk '{ print $2 }'`

# create personal mailfolders

for ldappersonaldir in $ldappersonaldirs
	if [ ! -d $ldappersonaldir ]
		mkdir -p `dirname $ldappersonaldir`
		maildirmake $ldappersonaldir

for ldapshareddir in $ldapshareddirs
	ldapsharedmaildir=`dirname $ldapshareddir | sed 's/\/shared\//\/shared\.maildirs\//g'`
	shared_dn=`ldapsearch -x -w $systempass -D "$systemleave" -b "$accountleave" "(mailMessageStore=$ldapshareddir)" uid | grep "^[^#]" | grep "^dn:" | sed 's/^dn: //g'`
	shared_uid=`ldapsearch -x -w $systempass -D "$systemleave" -b "$accountleave" "(mailMessageStore=$ldapshareddir)" uid | grep "^[^#]" | grep "^uid:" | sed 's/^uid: //g'`
	shared_boxes=`ldapsearch -x -w $systempass -D "$systemleave" -b "$accountleave" "(mailMessageStore=$ldapshareddir)" postOfficeBox | grep "^[^#]" | grep "^postOfficeBox:" | sed 's/^postOfficeBox: //g'`
	shared_cn=`ldapsearch -x -w $systempass -D "$systemleave" -b "$accountleave" "(mailMessageStore=$ldapshareddir)" cn | grep "^[^#]" | grep "^cn:" | sed 's/^cn: //g'`
	subscribed_dirs=`ldapsearch -x -w $systempass -D "$systemleave" -b "$accountleave" "(&(accountStatus=active)(seeAlso=$shared_dn))" mailMessageStore | grep "^[^#]" | grep mailMessageStore | awk '{ print $2 }'`

	# create shared mailfolder

	if [ ! -d $ldapsharedmaildir ]
                maildirmake -S $ldapsharedmaildir

	# create shared subfolders

	if [ ! -d $ldapsharedmaildir/.$shared_uid ]
		maildirmake -s write -f $shared_uid $ldapsharedmaildir

	# create other shared subfolders
	for box in $shared_boxes
		if [ ! -d $ldapsharedmaildir/.$box ]
			maildirmake -s write -f $box $ldapsharedmaildir

	# mailstorage directory

	if [ ! -d $ldapshareddir ]
	        mkdir -p `dirname $ldapshareddir`

	# link mailstorage to incoming shared folder

	dirlink=`echo $ldapshareddir | sed 's/\/$//g'`

	if [ ! -L $dirlink ]
		ln -s $ldapsharedmaildir/.$shared_uid $dirlink

	# subscribe those who have a 'seeAlso' to the dn of the shared account

	for subscribed_dir in $subscribed_dirs
		groupname=`echo $shared_cn | sed 's/ /_/g'`
		if [ -e $subscribed_dir/shared-maildirs ]
			subscribed=`cat $subscribed_dir/shared-maildirs | grep ^$groupname[[:space:]] | awk '{ print $1 }'`

		if [ ! $subscribed ]
			maildirmake --add $groupname=$ldapsharedmaildir $subscribed_dir

1.9 About sldapd.conf

The slapd.conf contains a ''index objectClass,uid,mail,mailAlternateAddress eq'' for performance reasons and a ''allow bind_v2'', which was needed for postfix at some moment.

The acl's of the ldap server don't allow anonymous reading of the ldap data, anonymous can only authenticate, that's why the smtp and imap server have to bind as ''system-leave'', and ''System'' has a password. If anonymous reads would be allowed, the servers could do without binding.

2 The smtp server

2.1 Overview

The smtp server is configured once in /etc/postfix/main.cf, after that all users and domains can be added and removed without changing the configuration file. On multiple smtp servers, with a central mail storage (e.g. nfs), all smtp servers can have exactly the same configuration file. Three parameters are ldap based, mydestination, virtual_maps and virtual_mailbox_maps.

2.2 Virtual delivery

All mail is owned by one user, in this case the user is ''vmail'', with unix uid 5000 and unix gid 5000, in main.cf this is configured as:

local_transport = virtual
virtual_mailbox_base = /
virtual_mailbox_maps = ldap:ldapvirtual
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
virtual_minimum_uid = 500
virtual_mailbox_limit = 0
ldapvirtual_server_host = ldapserverhostname
ldapvirtual_server_port = 389
ldapvirtual_bind = yes
ldapvirtual_bind_dn = system-leave
ldapvirtual_bind_pw = ldapSystemPassword
ldapvirtual_search_base = account-leave
ldapvirtual_query_filter = (&(|(mail=%s)(mailAlternateAddress=%s))(|(AccountStatus=active)(accountStatus=shared)))
ldapvirtual_result_attribute = mailMessageStore

2.3 mydestination

The local domains are looked up in ldap, this is configured in main.cf:

mydestination = $myhostname, localhost.$mydomain, localhost.localdomain, ldap:acceptdomains
acceptdomains_server_host = ldapserverhostname
acceptdomains_server_port = 389
acceptdomains_bind = yes
acceptdomains_bind_dn = system-leave
acceptdomains_bind_pw = ldapSystemPassword
acceptdomains_search_base = ou=postfix,system-leave
acceptdomains_query_filter = (associatedDomain=*)
acceptdomains_result_attribute = associatedDomain

2.4 virtual_maps

These lookups are responsible for seeing the mailAlternateAddress as an alias, this part is configured in main.cf as:

virtual_maps = ldap:ldapalias
ldapalias_server_host = ldapserverhostname
ldapalias_server_port = 389
ldapalias_bind = yes
ldapalias_bind_dn = system-leave
ldapalias_bind_pw = ldapSystemPassword
ldapalias_search_base = account-leave
ldapalias_query_filter = (&(|(mail=%s)(mailAlternateAddress=%s))(|(AccountStatus=active)(AccountStatus=shared)))
ldapalias_result_attribute = mail

3 The imap server

3.1 Overview

The imap server is a standard courier-imap installation the ldap configuration is in ''authldaprc'', it uses the mailMessageStore attribute to find the users' maildir, and authenticated with the ldap password.

3.2 Authldaprc

The authldaprc is configured as follows:

LDAP_SERVER		ldapservername
LDAP_BASEDN		account-leave
LDAP_BINDDN		system-leave
LDAP_BINDPW		ldapSystemPassword
LDAP_FILTER             (AccountStatus=active)
LDAP_HOMEDIR		mailMessageStore
LDAP_MAILDIR		mailMessageStore
LDAP_CRYPTPW		userPassword

3.3 Shared folders

All shared folders and the users who have access to it are created with maildirmake commands in the script makeMailMessageStoreDirs (see above).

About this document ...

ldap, postfix and courier-imap howto

This document was generated using the LaTeX2HTML translator Version 2002-1 (1.68)

Copyright © 1993, 1994, 1995, 1996, Nikos Drakos, Computer Based Learning Unit, University of Leeds.
Copyright © 1997, 1998, 1999, Ross Moore, Mathematics Department, Macquarie University, Sydney.

The command line arguments were:
latex2html -no_subdir -split 0 -show_section_numbers /tmp/lyx_tmpdir3842mb3hRe/lyx_tmpbuf0/postfix-courier-ldap-howto.tex

The translation was initiated by Administrative Account on 2003-05-16

next_inactive up previous
Administrative Account 2003-05-16