Postfix + Dovecot with LDAP Integration: Continuation

Purpose:
Configure Postfix and Dovecot to use OpenLDAP for alias resolution and mailbox delivery, allowing one real mailbox (testuser@example.com) to receive mail for many virtual addresses (e.g., admin, webmaster, postmaster).

This is part two and if you missed part one it is here.


Step 0: Prerequisites

  • Operating System: Debian 12
  • LDAP server running at ldap://127.0.0.1, base dc=example,dc=com
  • phpldapadmin installed (optional for LDAP entry management)
  • Root or sudo access

Step 1: Install Required Packages

apt update -y

apt install -y \
postfix postfix-ldap \
dovecot-core dovecot-imapd dovecot-pop3d dovecot-ldap dovecot-lmtpd \
sasl2-bin libsasl2-modules mailutils mutt
  • Postfix: main MTA and LDAP lookup support
  • Dovecot: IMAP, POP3, LMTP, LDAP auth
  • mailutils & mutt: testing clients

During Postfix install, choose “Internet Site” and set example.com as the mail name if it shows something else.


Step 2: Configure Postfix for LDAP Lookups

2.1 LDAP Aliases (/etc/postfix/ldap-aliases.cf)

vim /etc/postfix/ldap-aliases.cf

Add:

version          = 3
server_host      = 127.0.0.1
server_port      = 389

# point at your people tree
search_base      = ou=people,dc=example,dc=com
scope            = sub
bind             = no

# match ONLY on mailAlias
query_filter     = (&(objectClass=mailAccount)(mailAlias=%s))

# return the real mailbox
result_attribute = mailAddress
# If you add the following line you get a listing of all of the user aliases.
# result_attribute = mailAlias

timeout          = 5

2.2 LDAP Mailboxes (/etc/postfix/ldap-mailboxes.cf)

vim /etc/postfix/ldap-mailboxes.cf

Add:

version        = 3
server_host    = 127.0.0.1
server_port    = 389
search_base    = ou=people,dc=example,dc=com
scope          = sub
bind           = no
query_filter   = (&(objectClass=posixAccount)(mailAddress=%s))
result_attribute = homeDirectory

2.3 Main Configuration (/etc/postfix/main.cf)

Backup the file temporarily.

cp /etc/postfix/main.cf /tmp

Open:

vim /etc/postfix/main.cf

Add and modify:
Remove example.com from mydestination:

mydestination = $myhostname, localhost.$mydomain, localhost

Add your virtual settings:

# virtual domains
virtual_mailbox_domains = example.com

# mailbox lookup: map user@example.com → homeDirectory (/home/testuser)
virtual_mailbox_maps = ldap:/etc/postfix/ldap-mailboxes.cf

# alias lookup: map admin@example.com → testuser@example.com, etc.
virtual_alias_maps = ldap:/etc/postfix/ldap-aliases.cf

# deliver via Dovecot LMTP
virtual_transport = lmtp:unix:private/dovecot-lmtp

# enable SMTP AUTH via Dovecot
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
smtpd_recipient_restrictions =
    permit_sasl_authenticated,
    permit_mynetworks,
    reject_unauth_destination

Step 3: Reload Postfix:

postfix reload

Step 4: Configure Dovecot for LDAP & LMTP

4.1 LDAP Driver (/etc/dovecot/dovecot-ldap.conf.ext)

vim /etc/dovecot/dovecot-ldap.conf.ext

For bind-as-user:

hosts           = 127.0.0.1
ldap_version    = 3
base            = ou=people,dc=example,dc=com
# enable binding as authenticating user
auth_bind       = yes
user_filter     = (&(objectClass=posixAccount)(|(uid=%u)(mailAddress=%u)))

for the above comment out the other line for base or add these lines there.

Or for password-compare:

hosts           = 127.0.0.1
ldap_version    = 3
base            = ou=people,dc=example,dc=com
pass_filter     = (&(objectClass=posixAccount)(|(uid=%u)(mailAddress=%u)))
pass_attrs      = userPassword=userPassword
default_pass_scheme = SSHA
user_filter     = (&(objectClass=posixAccount)(|(uid=%u)(mailAddress=%u)))
user_attrs      = homeDirectory=home,uidNumber=uid,gidNumber=gid

4.2 Enable in Dovecot

In /etc/dovecot/conf.d/10-auth.conf:

vim /etc/dovecot/conf.d/10-auth.conf

Modify:

!include auth-system.conf.ext
!include auth-ldap.conf.ext

Ensure /etc/dovecot/conf.d/auth-ldap.conf.ext points to the file above.

4.3 LMTP & SASL Socket (/etc/dovecot/conf.d/10-master.conf)

vim /etc/dovecot/conf.d/10-master.conf

Comment out the existing configuration and add:

service auth {
  unix_listener /var/spool/postfix/private/auth {
    mode = 0660
    user = postfix
    group = postfix
  }
}
service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
    mode = 0600
    user = postfix
    group = postfix
  }
}

4.4 Mail Location & Auto-Creation (/etc/dovecot/conf.d/10-mail.conf)

vim /etc/dovecot/conf.d/10-mail.conf

Note: Set mail location and check that there is a namespace inbox but stop there as the file 15-mailboxes.conf contains mailbox setup.

mail_location = maildir:~/Maildir

Verify this exists.

namespace inbox {...

4.5 Mail Location & Auto-Creation (/etc/dovecot/conf.d/15-mailboxes.conf)

Here is the mailbox configuraton. # NOTE: Assumes “namespace inbox” has been defined in 10-mail.conf. Most of what is added is the auto lines.

vim /etc/dovecot/conf.d/15-mailboxes.conf

Modify:

namespace inbox {
  # Added LDAP
  separator = /
  # These mailboxes are widely used and could perhaps be created automatically:
  mailbox Drafts {
    auto = subscribe
    special_use = \Drafts
  }
  mailbox Junk {
    special_use = \Junk
  }
  mailbox Trash {
    auto = subscribe
    special_use = \Trash
  }

  # 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 {
    auto = subscribe
    special_use = \Sent
  }
  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
  #}

  # If you have a virtual "Important" mailbox:
  #mailbox virtual/Important {
  #  special_use = \Important
  #  comment = All my important messages
  #}
}

Step 5: Restart Dovecot:

systemctl restart dovecot

Step 6: UNIX Accounts & Maildirs

LDAP UIDs/GIDs must exist locally:

Create matching group and user

groupadd -g 10000 testuser
useradd -u 10000 -g 10000 -m -d /home/testuser -s /usr/sbin/nologin testuser

Bootstrap Maildir

mkdir -p /home/testuser/Maildir/{new,cur,tmp}
chown -R testuser:testuser /home/testuser/Maildir

Next Steps:

Testing End-to-End and how this all works will be published soon as part three in this series.

Here is a zip file of this article in text which makes it easier to copy and paste.