local(8) is the Postfix daemon that decides whether your mail lands in a mailbox, gets forwarded, or vanishes into a silently misconfigured alias. This guide traces a recipient through aliases, a per-user .forward file, and mailbox delivery, then verifies the result without guessing which setting won. It uses Postfix 3.8.6, installed from Ubuntu package postfix 3.8.6-1ubuntu0.1. Allow about twenty minutes for a read-only inspection, or longer if you are changing a live mail system.
The local(8) daemon is not normally a command you run by hand. Postfix's master process starts it, and the queue manager gives it delivery requests. The practical controls are in main.cf, the aliases database, and users' home directories.
Run these ordinary, read-only commands as any user. They show the values that matter to the local delivery path on this host:
$ command -v postconf
/usr/sbin/postconf
$ postconf mail_version mail_spool_directory home_mailbox alias_maps forward_path
mail_version = 3.8.6
mail_spool_directory = /var/mail
home_mailbox = Maildir/
alias_maps = hash:/etc/aliases
forward_path = $home/.forward${recipient_delimiter}${extension}, $home/.forward
Your output may differ. The important trap here is precedence: aliases are checked before .forward, then optional transports and commands, then home_mailbox, mail_spool_directory, and fallback settings. Do not change a lower-priority setting while an alias is still catching the address.
Checkpoint: save the output somewhere outside the Postfix configuration directory if you need a before-and-after comparison. Do not paste secrets into a support ticket; these values can reveal mail routing.
System aliases are usually defined in /etc/aliases and compiled into the database named by alias_maps. Inspect both the text file and its database metadata:
$ ls -l /etc/aliases /etc/aliases.db
-rw-r--r-- 1 root root ... /etc/aliases
-rw-r--r-- 1 root root ... /etc/aliases.db
$ sed -n '1,40p' /etc/aliases
root: alice
For a real change, edit the aliases file with elevated privileges, keeping the destination explicit. A line such as alerts: alice sends mail for alerts to the local user alice. It does not make a new Unix account.
Warning: Changing aliases affects future mail for every local sender and can redirect operational notices. After editing, rebuild the database with the privileged command below:
# newaliases
# postalias -q alerts hash:/etc/aliases
alice
The query is a useful checkpoint. If it prints nothing, the database does not contain the entry you expected. If you need to undo the change, restore the previous line in /etc/aliases, run newaliases again, and query it once more.
For a recipient named alice, the default search path on this installation tries an extension-specific file first, then /home/alice/.forward. Address extensions are enabled by the active recipient_delimiter = +, so mail to alice+alerts can use .forward+alerts before the ordinary file.
$ postconf -h recipient_delimiter forward_path
+
$ namei -l /home/alice/.forward
$ test -r /home/alice/.forward && echo readable
readable
Forwarding runs with the recipient's privileges. The file must be readable by that user, and each parent directory needs execute permission for directory traversal. An empty .forward means do not forward mail. Its right-hand syntax can contain addresses, file destinations, commands, and :include: directives, but the active security controls can reject some of those destinations.
Keep a copy before changing a working forwarding rule. To disable forwarding without deleting the file, rename it as the recipient:
$ mv ~/.forward ~/.forward.disabled
$ test ! -e ~/.forward && echo forwarding-disabled
Undo that change with mv ~/.forward.disabled ~/.forward, then check the file ownership and permissions. Do not use sudo to create a user's forwarding file unless you also deliberately set its ownership and mode.
A UNIX-style spool mailbox is a single file, commonly /var/mail/USER. A home mailbox is selected with a relative home_mailbox path. A path ending in / requests qmail-compatible Maildir delivery, so the active Maildir/ value means a directory under the user's home directory.
$ postconf -h home_mailbox mail_spool_directory
Maildir/
/var/mail
$ ls -ld "$HOME/Maildir" "$HOME/Maildir/new" "$HOME/Maildir/cur" "$HOME/Maildir/tmp"
drwx------ ... /home/alice/Maildir
drwx------ ... /home/alice/Maildir/new
drwx------ ... /home/alice/Maildir/cur
drwx------ ... /home/alice/Maildir/tmp
Do not switch mailbox formats on a live account just to make a test easier. Mail clients configured for mbox and Maildir expect different layouts. A mailbox file is locked while delivery runs; Maildir uses separate message files and temporary delivery paths.
Command and file destinations are not harmless output redirections. The local agent runs external delivery with the receiving user's rights, or with default_privs when there is no user context. The defaults here allow commands and files from aliases and forwarding files, but not from :include: files:
$ postconf allow_mail_to_commands allow_mail_to_files default_privs command_time_limit
allow_mail_to_commands = alias, forward
allow_mail_to_files = alias, forward
default_privs = nobody
command_time_limit = 1000s
Postfix resets PATH to a system default before launching a command. It also exports a limited set of recipient and sender variables, including USER, RECIPIENT, SENDER, and HOME. Do not place untrusted address text into a shell fragment, and do not loosen allow_mail_to_commands or allow_mail_to_files merely to silence a delivery error.
External files and commands can occasionally receive a message more than once because their delivery status is not checkpointed to disk. Make any consumer idempotent, especially if it writes to a database or triggers another action.
Use a test recipient that you control. Sending mail changes queue and mailbox state, so use a non-sensitive subject and do not test against a production list. A normal unprivileged test with the local sendmail interface is:
$ printf 'Subject: local delivery check\n\nlocal delivery test\n' | sendmail -v alice
alice... deliverable: mailer local, user alice
The exact verbose text depends on your Postfix build. Check the exit status, then inspect the destination selected earlier:
$ printf 'sendmail exit status: %s\n' "$?"
sendmail exit status: 0
$ find "$HOME/Maildir/new" -maxdepth 1 -type f -printf '%f\n'
...
If the message is deferred or bounced, inspect the mail log as an administrator. The manual says that transactions and problems are logged through syslog or postlogd; the exact log file is distribution-specific. On systems using systemd's journal, try:
# journalctl -u postfix --since '10 minutes ago'
After changing main.cf, Postfix processes pick up the setting automatically as new local processes start, but postfix reload speeds that up:
# postfix check
# postfix reload
Use postfix check before a reload. A reload is service-affecting, although it is normally brief. If a change causes trouble, restore the previous configuration, run postfix check, and reload again. Keep the original message and the relevant log lines while investigating.
newaliases and a targeted postalias -q check.