Add a Local Postfix Filter Service Safely
You will add a Postfix SMTP client service and a loopback-only SMTP listener to /etc/postfix/master.cf, then check exactly what changed. The installed command is postfix-add-filter from Postfix 3.8.6-1ubuntu0.1 on this system. Allow about fifteen minutes, plus time to test the filter that will connect to the new listener.
The route
Jump straight to the step you need, or tick off Done means at the end.
You need Postfix installed, an SMTP filter that understands the generated arrangement, and an account allowed to use sudo. The command changes a live configuration file. It does not install or configure amavisd-new, clamsmtp or any other filter, and it does not reload Postfix for you.
1. Check the installed command before editing Postfix
This is an ordinary, read-only check:
$ command -v postfix-add-filter
/usr/sbin/postfix-add-filter
$ dpkg-query -W -f='${Package} ${Version}\n' postfix
postfix 3.8.6-1ubuntu0.1
$ postfix-add-filter
To add a new filter service to your master.cf:
% sudo postfix-add-filter {smtp client name} {smtpd service port}
Example:
% sudo postfix-add-filter amavisfeed 10025
The command's local manpage describes the first argument as an SMTP service name and the second as an SMTPD port. Despite the usage text calling the first value an SMTP client name, it becomes the service name in master.cf. Use a short name that does not already occur in that file, and choose a port reserved for this filter.
Checkpoint
Record the exact values you intend to use. The examples below use FILTER_SERVICE as a placeholder and port 10025. Replace both deliberately rather than pasting the placeholder.
2. Inspect the existing service and port
Run these checks without elevated privileges if your account can read the file:
$ sudo grep -nE '(^|[[:space:]])FILTER_SERVICE([[:space:]]|$)|127\.0\.0\.1:10025' /etc/postfix/master.cf
$ sudo ss -ltn '( sport = :10025 )'
No output from either command is the useful result. If either value is already present, choose different values. The utility refuses to modify master.cf when the service name or port text appears anywhere in the file, but its test is a simple substring search. A coincidence elsewhere can therefore cause a false refusal, and an uncareful choice can collide with a different service.
Do not use a public address for this generated listener. The script writes 127.0.0.1:PORT, so the SMTP filter and Postfix must communicate on the same host. A filter on another machine needs a separately designed, authenticated transport rather than a casual edit to this example.
3. Add the filter service
This is the state-changing step and requires elevated privileges:
$ sudo postfix-add-filter FILTER_SERVICE 10025
For a real service, an invocation might be:
$ sudo postfix-add-filter amavisfeed 10025
The script copies the original file to a timestamped backup such as /etc/postfix/master.cf.1712345678, builds /etc/postfix/master.cf.working, appends the generated services, and moves that working file into place. The timestamp in the example is illustrative; use the filename printed by your own directory listing when recovering.
It adds an SMTP client service named amavisfeed with a process limit of 2 and options for the filter protocol. It also adds 127.0.0.1:10025 as an SMTPD service. That listener permits only clients matched by mynetworks, which the generated entry sets to 127.0.0.0/8, and clears the normal content-filter and milter settings for this reinjection path.
Warning
The generated listener is intentionally permissive for trusted local reinjection, not for untrusted network traffic. A local process that can reach it may be able to submit mail according to the generated restrictions. Review the security model of every process that can connect to loopback before enabling this in production.
4. Confirm the generated entries
Inspect the end of the file and the relevant service lines:
$ sudo grep -n -A24 -B2 'Added using postfix-add-filter script' /etc/postfix/master.cf
$ sudo grep -n -E '^amavisfeed[[:space:]]+unix|^127\.0\.0\.1:10025[[:space:]]+inet' /etc/postfix/master.cf
42:amavisfeed unix - - - - 2 smtp
48:127.0.0.1:10025 inet n - - - - smtpd
The line numbers will differ. Check that the service name, port, loopback address and filter-specific overrides match your plan. In particular, do not accidentally accept a generated listener bound to a non-loopback address after manually editing it.
Postfix reads service definitions from master.cf, while the filter's connection to the service must be configured separately. The generated file does not set content_filter in main.cf, create a transport map, or tell Postfix which messages should pass through the filter.
5. Validate before reloading
Run Postfix's configuration check before asking the master process to reread the file:
$ sudo postfix check
$ sudo postfix reload
A successful postfix check normally produces no output. The reload is a separate, service-affecting action. Do it only after the generated entries and the filter's own configuration are ready. If the check fails, do not reload; fix the reported configuration problem or recover the previous file first.
After reloading, confirm that the listener exists:
$ sudo ss -ltn '( sport = :10025 )'
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 100 127.0.0.1:10025 0.0.0.0:*
The queue sizes vary. If there is no listener, inspect the Postfix log and the service definition rather than opening the port publicly. A listening socket alone does not prove that the filter is processing mail correctly; send a controlled test message only after the filter's integration settings are complete.
6. Recover if the change is wrong
The command's backup is the simplest undo path. First list the backups and identify the one created immediately before your change:
$ sudo ls -lT /etc/postfix/master.cf /etc/postfix/master.cf.*
Warning
Restoring a backup discards later edits to master.cf. Compare the files before replacing anything, and stop if another administrator or automation changed the file after your run.
$ sudo diff -u /etc/postfix/master.cf /etc/postfix/master.cf.TIMESTAMP
$ sudo cp --preserve=mode,ownership /etc/postfix/master.cf.TIMESTAMP /etc/postfix/master.cf
$ sudo postfix check
$ sudo postfix reload
Replace TIMESTAMP with the actual backup suffix. Keep the backup until the replacement has been checked and the service has returned to the expected state. If the utility refuses because a name or port already appears, it says that master.cf was not modified; do not restore a backup in that case.
7. Account for the command's fixed configuration path
The manpage documents MAIL_CONFIG, but also warns that this version of postfix-add-filter currently ignores it and is hard-coded to /etc/postfix. Do not use MAIL_CONFIG as a test that redirects this command to a staging directory. If you need an isolated test, copy the script's generated service text into a disposable configuration under a controlled procedure, or test on a disposable host.
Done means
- The installed Postfix version and command syntax were checked.
- The service name and port were confirmed to be unused.
- A timestamped
master.cfbackup exists. - The new SMTP service and loopback listener match the intended values.
postfix checkpassed before any reload.- The listener is bound to loopback and the filter integration has been tested.
- You know which backup to compare and restore if the change must be undone.