Postfix to Dovecot Delivery with LMTP and LDA
LMTP gives Postfix a per-recipient final-delivery result while Dovecot applies mailbox, quota and Sieve logic under the correct virtual identity. This lesson treats Postfix to Dovecot LMTP delivery as one decision point in a longer message path. The configuration is useful only when an operator can show which message entered it, which identity and rule matched, what the next daemon returned, and how a failure is retried or contained.
Prerequisites and inherited lab checkpoint
Lessons 8 and 9 must provide a working virtual user, Maildir, TLS submission and private service sockets.
For the Postfix to Dovecot LMTP delivery lab, use reserved domain example.test, documentation addresses and disposable messages. Preserve postconf -n, postconf -M, package versions, DNS answers and a queue baseline before changing the lab. Keep console access and do not copy credentials, private keys or customer messages into the evidence record.
Install and prepare the required components
sudo dnf info postfix dovecot
sudo dnf install -y postfix dovecot
sudo cp -a /etc/dovecot/conf.d/10-master.conf /etc/dovecot/conf.d/10-master.conf.before-nitwings
rpm -q postfix dovecot- Confirm package availability and ownership in the enabled RHEL repositories before adding a third-party source. Record the repository, signing key fingerprint, version and support lifecycle.
- A package install creates files and service identities; it does not establish safe relay, authentication, delivery or filtering behavior.
- Back up only the files this lesson changes and record modes, owners and SELinux labels so rollback restores more than text.
- Use
systemctl cat, package file lists and local manual pages to identify paths on the installed build instead of assuming a path from another distribution.
Build the Postfix to Dovecot LMTP delivery configuration and understand every boundary
Create a Postfix-chroot-visible LMTP socket and select it as the virtual transport.
# Dovecot 10-master.conf
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0600
user = postfix
group = postfix
}
}
protocol lmtp {
postmaster_address = [email protected]
}
# Postfix main.cf
virtual_transport = lmtp:unix:private/dovecot-lmtp
virtual_mailbox_limit = 0The Postfix path is relative to its queue directory; Dovecot uses the full filesystem path. LMTP reports status for each recipient after content, unlike a single pipe exit for several recipients.
Verify the working path
sudo doveconf -n
sudo postfix check
sudo systemctl restart dovecot
sudo test -S /var/spool/postfix/private/dovecot-lmtp
sudo postfix reload
printf 'Subject: LMTP lab\n\ncheckpoint\n' | sendmail -v [email protected]
sudo doveadm search -u [email protected] mailbox INBOX HEADER Subject 'LMTP lab'- Run the syntax or lookup test before reload. A reload must never be the first parser of a production configuration.
- The positive test proves the intended path. The negative test proves an unauthorized sender, recipient or client is not accidentally accepted.
- Stop the named dependency in the disposable lab and verify temporary failure or controlled bypass matches the documented policy.
- Repeat the accepted path after restart and reboot, then compare effective configuration rather than only source files.
Production decisions before continuing
| Decision | Choose deliberately | Evidence to retain |
|---|---|---|
| Failure policy | When LMTP is unavailable, Postfix keeps the message queued and retries; it must not silently fall back to root-owned direct Maildir writes. | SMTP transcript, queue state and dependency alert |
| Trust boundary | Postfix may connect only to the private LMTP socket; Dovecot resolves the already validated virtual recipient to its mailbox identity. | Matching client, sender, recipient or daemon identity |
| Secrets and data | Restrict credentials, message samples and keys to the minimum service identity. | Owner, mode, label and secret rotation record |
| Activation | Validate, reload, run positive and negative tests, then watch one complete message. | Syntax output, queue ID and linked log events |
| Rollback | Restore the exact files and map/database state changed by this lesson. | Rollback command and repeated acceptance result |
Place Postfix to Dovecot LMTP delivery in the message path
LMTP is final delivery, not Internet SMTP. LDA remains useful for some local invocation cases, but the cumulative virtual-domain lab uses LMTP for recipient-specific status and Sieve/quota integration.Understand the component before configuring it
| Layer | Question to answer | Evidence |
|---|---|---|
| Input | Queued message and one or more validated recipients | SMTP transcript, lookup input or message header |
| Decision | Dovecot user lookup, quota, Sieve and mailbox transaction | Effective configuration and exact matched rule |
| Output | Per-recipient 2.x, 4.x or 5.x LMTP status | Queue state, delivery status or downstream response |
| Dependency | Private socket, SQL userdb, mailbox storage and filesystem capacity | Socket, timeout, journal and controlled outage test |
| Recovery | Can processing resume without duplicate, loss or unauthorized delivery? | Retained queue ID, backup and repeated acceptance |
Build it step by step
- Draw the path. Mark the connection, envelope, content and authenticated identities available at this stage.
- Inventory the effective state. Capture package version, active service, sockets, Postfix parameters, master services and lookup results.
- Prepare one coherent configuration. Substitute documented lab values and verify ownership, mode and SELinux context.
- Validate before activation. Run component syntax checks, map queries and a non-delivering test where supported.
- Exercise three outcomes. Send an intended message, an intended denial and a message while the named dependency is unavailable.
- Trace one queue ID. Join ingress, policy, filtering, routing and final delivery events without relying on subject text.
- Close the change. Restart or reboot where relevant, repeat tests, check queue age and document rollback.
Operate and inspect the component
postconf virtual_transport
sudo doveconf -n
sudo doveadm user [email protected]
sudo doveadm mailbox status -u [email protected] messages vsize INBOX
postqueue -p
postcat -q QUEUE_ID
journalctl -u postfix -u dovecot --since '-15 minutes'- Replace sample hostnames, addresses and queue IDs only after resolving them from the lab. Do not paste production identities into a public command transcript.
postconf -nshows non-default global parameters;postconf -Mandpostconf -Pexpose master service and field overrides.- A successful lookup proves only that input. Test present, absent, disabled and dependency-unavailable results separately.
- Use the queue ID as the correlation key. Message subjects and recipient addresses are not unique and may contain sensitive information.
Evidence and acceptance criteria
| Evidence | Healthy result | Failure meaning |
|---|---|---|
| Syntax | All component validators succeed before activation | The running service would parse an unreviewed or invalid state |
| Positive path | One message appears once in the intended Maildir and LMTP records success for that recipient. | The intended message cannot complete this decision point |
| Negative path | A nonexistent or disabled user is rejected by recipient policy and cannot create a mailbox. | The configuration may relay, authenticate, route or deliver too broadly |
| Dependency failure | Stopping Dovecot leaves the message deferred; restart delivers it once. | Messages may be lost, permanently rejected or silently bypass controls |
| Persistence | Effective state and tests agree after restart and reboot | Only transient state was changed |
Direct Maildir delivery bypasses quota and Sieve
Postfix writes files through a virtual delivery transport while Dovecot separately serves IMAP. Messages arrive, but user rules and quota policy never run and ownership differs. Moving final delivery to Dovecot LMTP restores one mailbox writer and per-recipient status.Troubleshooting by symptom
| Symptom | Inspect first | Defensible next action |
|---|---|---|
| Connect to socket fails | both path interpretations, owner and parent traversal | Correct the chroot-visible socket |
| Delivered but absent in IMAP | userdb home, namespace and actual Maildir | Resolve both services to one location |
| Duplicate message after retry | LMTP transaction logs and queue ID | Find lost acknowledgement before requeueing |
| Quota response wrong | Dovecot quota state and backend | Recalculate or repair the authoritative quota data |
Unsafe operations and recovery boundaries
- Unsafe: manually copying mail into new without ownership and filename discipline can corrupt state.
- Unsafe: deleting a deferred message because delivery is slow causes permanent loss.
- Unsafe: granting Postfix broad write access to all mailbox storage removes the LMTP boundary.
Rewritten knowledge checks
Cumulative lab checkpoint
- Capture the inherited checkpoint and state the exact sender, recipient, client address and expected SMTP result.
- Install the required package from a recorded source and save the package/file/service inventory.
- Apply the complete lab configuration, including permissions, socket paths, map generation and service ownership.
- Run syntax and lookup validation, then activate without closing the recovery session.
- Complete positive, negative and dependency-outage tests while retaining queue IDs and UTC logs.
- Restart the participating services, repeat the accepted path and confirm no unexplained deferred mail remains.
- Execute rollback once, prove the previous behavior, then reapply the reviewed state as the checkpoint for the next lesson.