Rewrite the Postfix bounce messages your users see, and preview the result before a single one goes out. You will finish with a previewed bounce template, a controlled configuration change and a rollback path. Allow about twenty minutes, plus time to deliver a test message through your own mail flow.
The examples use Postfix 3.8.6, installed here as package version 3.8.6-1ubuntu0.1.
/etc/postfix, reloading Postfix, and reading its queue or logs normally need elevated privileges.Confirm the package version and the active template setting before changing anything:
$ postconf mail_version
mail_version = 3.8.6
$ postconf bounce_template_file bounce_size_limit enable_threaded_bounces header_from_format
bounce_template_file =
bounce_size_limit = 50000
enable_threaded_bounces = no
header_from_format = standard
What the values mean:
bounce_template_file: Postfix uses its built-in templates.bounce_size_limit: limits the original message text included in a non-delivery notice. It is not a limit on the template itself.enable_threaded_bounces: in Postfix 3.6 and later it can add References: and In-Reply-To: headers. It is disabled by default here.Checkpoint: Record the output of postconf -n somewhere you can consult during recovery. Do not treat a copied example as your current configuration.
Start from the packaged example when your distribution has one. The local package does not install /etc/postfix/bounce.cf.default, so look for a suitable example instead of inventing a complete template:
$ find /usr/share /usr/lib -type f -name 'bounce.cf*' -print 2>/dev/null
If that prints an example, copy it to a private file under /tmp and edit the copy. If it prints nothing, use this small failure template as a known-valid starting point:
failure_template = <<EOF
Charset: us-ascii
From: MAILER-DAEMON (Mail Delivery System)
Subject: Undelivered Mail Returned to Sender
Postmaster-Subject: Postmaster Copy: Undelivered Mail
This is the mail system at host $myhostname.
The message could not be delivered to one or more recipients.
The original message is attached below.
EOF
Template rules to remember:
<< ends the template and must appear alone on its closing line.# are ignored.$$ for a literal dollar sign.Charset: to an appropriate superset of US-ASCII.Warning: Do not paste secrets, internal credentials or sensitive diagnostic data into a notification that may leave your system.
Run the preview as the account that can read the file:
$ postconf -b /tmp/postfix-bounce.cf
From: MAILER-DAEMON (Mail Delivery System)
Subject: Undelivered Mail Returned to Sender
Postmaster-Subject: Postmaster Copy: Undelivered Mail
This is the mail system at host mail.example.invalid.
The message could not be delivered to one or more recipients.
The original message is attached below.
Your hostname will differ. Errors go to standard error and to the mail log, so a preview that emits an error is not ready to install.
Watch the time expansions in particular. $maximal_queue_lifetime_days expands the configured queue lifetime in days, and $delay_warning_time_hours expands the warning time in hours. These names are special to the bounce template format. Use only parameter names that exist in main.cf or are documented by bounce(5).
Checkpoint: Run the preview again after the final edit, save its output for comparison, and check that the subject, sender and hostname are what you expect. Previewing does not send mail and does not alter Postfix.
Warning: This changes future generated delivery status notifications. Use root privileges only for the copy and the configuration edit, and keep the old value for rollback.
$ sudo install -o root -g root -m 0644 /tmp/postfix-bounce.cf /etc/postfix/bounce.cf
$ sudo postconf -e 'bounce_template_file = /etc/postfix/bounce.cf'
$ postconf bounce_template_file
bounce_template_file = /etc/postfix/bounce.cf
Postfix picks up main.cf changes automatically as bounce processes are replaced, but the installed manual recommends postfix reload when you want the change sooner. Reloading is a service operation. It does not discard the queue, but skip it during a change window where reloads are forbidden:
$ sudo postfix check
$ sudo postfix reload
postfix/postfix-script: refreshing the Postfix mail system
The exact reload message can vary by packaging. The useful checks are the command status and the resulting configuration:
$ printf 'reload status: %s\n' "$?"
reload status: 0
$ postconf bounce_template_file
bounce_template_file = /etc/postfix/bounce.cf
Send a test message only through a controlled route, to a mailbox you own. To test a bounce, use a recipient address that your mail policy deliberately rejects, not a random real address. Capture the queue ID from your normal submission command, then check your mail log for the bounce service and the generated notification.
The daemon keeps per-message status files under the queue service directories. On this system those are:
$ sudo find /var/spool/postfix/bounce /var/spool/postfix/defer /var/spool/postfix/trace -maxdepth 1 -type f -print
Warning: Do not edit or remove those files by hand.
Here is what happens to them. A bounce request can append a recipient delivery record, then enqueue a delivery status notification containing the record and the original message. After a successful enqueue, the status file is deleted. The same daemon serves the bounce, defer and trace service names. They represent non-delivery and delivery-status roles in the queue, not three separate commands to run manually.
If the preview reports an error, fix the temporary file and preview again. If a deployed template produces malformed notices, stop using it immediately by restoring the built-in behaviour:
$ sudo postconf -e 'bounce_template_file ='
$ sudo postfix check
$ sudo postfix reload
$ postconf bounce_template_file
bounce_template_file =
Recovery: That is the undo for this guide's configuration change. Keep /etc/postfix/bounce.cf until you have confirmed the built-in notices are acceptable, then remove it only if you no longer need it and your change-control process allows the deletion.
Check logs with the platform's normal journal or syslog tooling. The daemon reports problems and transactions to syslogd or postlogd.
One subtle boundary matters here: Postfix makes a best notification effort. It can send a non-delivery notification even when the per-message log or original message cannot be read. A notice proves that Postfix attempted notification, not that every original detail was available.
postconf -b shows the template without errors.postfix check and postfix reload return success.bounce_template_file and reload to return to the built-in templates.