Log Shell Script Messages through Postfix with postlog
You will finish with a shell script that sends one message, or one message per input line, through the Postfix-compatible postlog interface. The installed command is Postfix 3.8.6 from package version 3.8.6-1ubuntu0.1. Allow about ten minutes. You need the postfix package and a shell; most examples run as an ordinary user.
The route
Jump straight to the step you need, or tick off Done means at the end.
Safety checkpoint
This command writes log records. It does not send an email by itself, but the records may be forwarded to a central logger or retained in a location with different access controls. Do not put passwords, tokens or private message content in a log line.
1. Confirm the installed command
Check which executable your shell will use and record the Postfix version:
$ command -v postlog
/usr/sbin/postlog
$ postconf mail_version
mail_version = 3.8.6
The manpage describes postlog as a Postfix-compatible logging interface for shell scripts. On this machine the binary is installed by the postfix package. It is normally usable without sudo; do not grant it extra permissions or change its ownership to make a script work.
Checkpoint: if command -v postlog prints nothing, stop here and use your normal package-management process to install or repair Postfix. Installing packages changes system state and is outside the logging test itself.
2. Write one record with a useful tag
Pass the message as the remaining arguments and select a tag that identifies the script:
$ postlog -t backup-check 'backup pre-flight passed'
postfix/postlog: backup pre-flight passed
$ printf '%s\n' "$?"
0
The command treats the text arguments as one record. The installed command prints the record on the terminal when its standard error is connected to a terminal, and also sends logging to syslogd or postlogd. The displayed prefix includes the Postfix process name and the message. A non-zero status means the logging operation failed, so capture it if the script cannot continue safely.
Keep the tag short and stable. A tag is the identifying name at the start of each record, not a free-form replacement for the message. If you omit -t, Postfix supplies a default tag:
$ postlog 'message with the default tag'
Use -- before text beginning with a hyphen if you need to make it unambiguously a message rather than an option:
$ postlog -t backup-check -- '-temporary file was not found'
That form is useful in scripts where a variable may start with -. Quote variables so that spaces stay within the intended record.
3. Set a severity deliberately
Use -p for the logging severity. The accepted values are info, warn, error, fatal and panic; info is the default:
$ postlog -p warn -t backup-check 'archive is older than expected'
postfix/postlog: archive is older than expected
$ postlog -p error -t backup-check 'archive verification failed'
Choose the level for the condition, not for how much output you want. The command rejects an unknown severity:
$ postlog -p nonsense -t backup-check 'not sent'
postfix/postlog: fatal: bad severity: "nonsense"
$ printf '%s\n' "$?"
1
Do not test fatal or panic casually in a production script. Postfix 3.1 and later pause for one second after reporting either condition. They are failure severities, not ordinary debug levels. If a test must exercise that path, do it in an isolated shell and account for the deliberate delay.
4. Log a stream one line at a time
When no message arguments are supplied, postlog reads standard input and logs each input line as one record. This makes it suitable for a small loop or for another command's text output:
$ printf '%s\n' 'started' 'checked 12 files' 'finished' | postlog -t backup-check
postfix/postlog: started
postfix/postlog: checked 12 files
postfix/postlog: finished
$ printf '%s\n' "$?"
0
Newlines separate records in this mode. Do not pipe arbitrary command output into the logger if it can contain secrets or untrusted, high-volume data. A noisy producer can fill the logging path and make the useful records harder to find. If you need one summary, capture and sanitise the result first, then call postlog once.
5. Put the call in a script and preserve errors
A direct call is enough for a best-effort notice. For an operational check, keep the logging result separate from the result of the work being checked:
if postlog -p info -t backup-check 'backup pre-flight passed'; then
printf '%s\n' 'log record accepted'
else
status=$?
printf 'could not write backup log, status %s\n' "$status" &2
exit "$status"
fi
Do not use a successful log call as proof that a backup, deployment or repair succeeded. It only reports that this logging attempt completed successfully. Check the actual operation independently.
For a diagnostic run, add -v. Multiple -v options increase verbosity. Remove the option after troubleshooting so routine logs stay readable.
6. Understand configuration without editing it
By default, the command reads Postfix's main.cf from the configured directory. On this host, ask Postfix where that directory is:
$ postconf -h config_directory
/etc/postfix
Use -c /path/to/configuration to read main.cf from a named directory for a particular invocation. The MAIL_CONFIG environment variable also identifies a directory containing main.cf. Treat alternate configuration directories as an administrative change: verify their ownership and contents before using them, and do not point a privileged Postfix logging path at a directory writable by an untrusted user.
The relevant configuration affects where records go. syslog_facility defaults to the mail facility in the installed configuration, and syslog_name supplies a prefix for the process name in syslog records. Postfix 3.4 and later can also use the postlogd service, with maillog_file selecting its optional logfile and postlog_service_name naming the service entry. Inspect those settings with postconf before promising a particular logfile:
$ postconf syslog_facility syslog_name maillog_file postlog_service_name
syslog_facility = mail
syslog_name = ${multi_instance_name?{$multi_instance_name}:{postfix}}
maillog_file =
postlog_service_name = postlog
Exact output varies with local configuration. The empty maillog_file shown here means no optional Postfix logfile is selected by that parameter. It does not mean the record is discarded; the active syslog or Postfix logging setup decides where it is handled.
7. Avoid obsolete and dangerous assumptions
The -i option is obsolete. It used to request a process ID in the tag, but Postfix 3.4 and later always include the PID, so do not build new scripts around it. The PID is diagnostic context, not a stable job identifier; use an explicit tag or message field for correlation.
The command is designed to work with set-group-ID privileges when connecting to postlogd. Do not copy that permission model to a hand-built wrapper, and do not use chmod or chown as a workaround. If logging fails, inspect the command status, the Postfix configuration and the service or system logger. Changing Postfix service configuration can affect other mail and logging operations, so make a backup and follow your site's change process before editing it.
Done means
postlogis available from the installed Postfix package and its version is known.- Single messages use a stable
-ttag and quote variable content. - Severity is one of the documented values, with
fatalandpanicreserved for genuine failure paths. - Stream input is used only for suitable, non-sensitive, bounded text.
- Scripts check
postlog's exit status without confusing it with the status of the operation being logged. - The active configuration and logging destination have been inspected before relying on a particular logfile or collector.