Home / Alt manpages / postlock(1)

  • postlock(1)
  • User command
  • linux

Run a Command While Postfix Locks a Mailbox

postlock holds an exclusive lock on a UNIX-style mailbox file while your command runs, so nothing else can corrupt it at the same time. Handy for a mailbox reader, a maintenance script, or anything else that must not race Postfix's own local delivery. Budget ten minutes for a first test. You need the Postfix package, a mailbox file you can read and write, and a command that is safe to run against it.

This describes the installed Postfix 3.8.6 command; the local manual page is the authority for the examples. Run them as the mailbox owner or another account with read/write permission. Do not reach for sudo unless your account genuinely cannot access the mailbox, and you have thought through the consequences first.

1. Confirm the installed command

Check which binary runs, and record the package version before building automation around it:

$ command -v postlock
/usr/sbin/postlock
$ postconf -h mail_version
3.8.6
$ postlock
postlock: fatal: usage: postlock [-c config_dir] [-l lock_style] [-v] folder command...

That usage line is the important boundary: the mailbox comes first, then the command and its arguments. postlock runs the command directly. It does not hand the remaining words to a shell for interpretation.

Checkpoint

If command -v finds nothing, install or repair Postfix through your normal package process before going further. If the version differs from 3.8.6, check the local postlock(1) page before copying any detail below into a script.

2. Pick a mailbox and a harmless test command

Use a real mailbox the current account can read and write. A typical path looks like /var/mail/alice, but never guess the path or account on your own host:

$ MAILBOX='/path/to/mailbox'
$ test -f "$MAILBOX" && test -r "$MAILBOX" && test -w "$MAILBOX" && echo 'mailbox is a writable regular file'
mailbox is a writable regular file

Swap in the real path: that check alone changes nothing. If it fails, fix the path or permissions first. Do not paper over it with sudo: running the child as root can leave files the normal mailbox owner can no longer manage.

For a first smoke test, use a command that only appends a marker line. That does change the mailbox, so make the marker deliberate, and use a disposable test mailbox where you can. Do not run it against a production mailbox purely to prove the command starts.

3. Run the command inside the lock

Pass the mailbox as the first argument to postlock. This example launches /usr/bin/sh explicitly, so the shell is the child command rather than something postlock inserts on your behalf:

$ postlock "$MAILBOX" /usr/bin/sh -c 'printf "postlock smoke test\n" >> "$1"' sh "$MAILBOX"
$ printf 'postlock status: %s\n' "$?"
postlock status: 0

The sh right after -c becomes the shell's $0; the mailbox path after that becomes $1. Slightly fussy, but it keeps the placeholder path out of the shell program text. Quote the path so spaces or shell metacharacters in it cannot rewrite your command line.

$ tail -n 3 "$MAILBOX"
postlock smoke test

Checkpoint

A status of zero means the child finished and postlock passed that status back. It does not prove every other mailbox-writing program respected the lock, or that a remote filesystem offers reliable exclusion. The lock only applies while the child runs; it is not a permanent permission change, and it will not turn an unsafe mailbox reader into a safe one on its own.

4. Keep the command and its arguments unambiguous

For a program with no shell syntax of its own, list the executable and each argument as separate words:

$ postlock "$MAILBOX" /usr/local/bin/mailbox-tool --check "$MAILBOX"

That assumes /usr/local/bin/mailbox-tool exists and takes those arguments; swap in your real program and read its own manual page. Do not hand postlock a single string like "/usr/local/bin/mailbox-tool --check $MAILBOX" and expect it to split or expand it. It will try to execute that entire string as a program name, and fail.

If you genuinely need redirection, pipes or conditionals, invoke the shell explicitly as in the smoke test above. Treat any path or data that came from someone else as untrusted, and never concatenate it into shell source without careful, separate quoting.

5. Configuration and diagnostics

By default postlock reads Postfix configuration from the configured directory, /etc/postfix on this installation. Use postconf to see the effective locking settings without editing anything:

$ postconf -h config_directory
/etc/postfix
$ postconf -h mailbox_delivery_lock
fcntl, dotlock

That value differs between hosts. -l LOCK_STYLE overrides the configured method for a single call, but only pick a value after checking your local postlock(1) page and Postfix configuration docs. -c CONFIG_DIR selects another configuration directory, and -v turns on verbose diagnostics; repeat it for more.

MAIL_CONFIG can also name the configuration directory, and MAIL_VERBOSE enables verbose logging. Be careful when these come from a service environment rather than your own shell: an unexpected configuration directory can silently change the locking behaviour. Check them with env or the service definition before you start debugging the mailbox itself.

6. Handle failures without guessing

If postlock cannot perform the requested operation, its own exit status is 75, also known as EX_TEMPFAIL. Any other status probably came from the child command, so capture it before running another diagnostic:

$ postlock "$MAILBOX" /usr/bin/false
$ status=$?
$ printf 'status: %s\n' "$status"
status: 1

That example deliberately uses false, which exits 1: nothing to do with locking. A 75, on the other hand, points at a lock, permission, configuration or resource problem: check the mailbox path, ownership, access mode and Postfix logs. Do not delete a lock file by hand just because a run is inconvenient; stale-lock cleanup, retry delay and attempt limits are already part of Postfix's own locking behaviour.

Warning

The manual is explicit that a lock acquired on a remote filesystem does not necessarily stop a conflicting process on another machine from touching the same file. Only run cooperating mailbox processes on a filesystem and locking arrangement you actually understand. If a command gets interrupted, inspect the mailbox and its logs before retrying anything that changes state.

Done means

  • Version confirmed. Installed Postfix version and local postlock(1) syntax checked.
  • Mailbox verified. A real mailbox with read/write access, no unnecessary sudo.
  • Command shape correct. Mailbox passed first, executable and arguments kept separate.
  • Result checked. Child status captured, and the mailbox result matches expectations.
  • Exit codes understood. 75 means postlock itself failed; anything else is the child's own status.
  • Limits acknowledged. No assumption that a remote filesystem, or a non-cooperating program, honours the lock.