Test a Postfix body_checks rule against real message lines before it rejects a single email. You will finish with a rule that logs a match, a repeatable way to test it without sending mail, and a safer path from observation to enforcement. Allow about fifteen minutes.
The examples use Postfix 3.8.6, installed from package postfix 3.8.6-1ubuntu0.1 on the machine where this guide was checked.
/etc/postfix and reloading Postfix need elevated privileges.REJECT, DISCARD and HOLD until the rule has been checked.Run these ordinary, read-only commands first:
$ postconf -h mail_version
3.8.6
$ postconf -m | grep -E '^(pcre|regexp)$'
pcre
regexp
body_checks is a lookup-table setting. The installed system supports both PCRE and POSIX regular-expression tables, so this guide uses PCRE. If the second command prints nothing, pick a table type listed by postconf -m and adjust the file syntax to its manual page.
Checkpoint: Record the output of postconf -h body_checks. It may be empty, which is the default and means no body rule is configured. If it already names a table, inspect that file before changing anything.
Use a dedicated file for the first test. This example matches a distinctive marker in a message body and logs a warning while processing carries on:
# sudo sh -c 'install -o root -g root -m 0644 /dev/null /etc/postfix/body_checks.pcre'
# sudo sh -c 'cat > /etc/postfix/body_checks.pcre <<"EOF"
/^BODY-CHECK-DEMO$/ WARN body_checks demo marker matched
EOF'
How the rule behaves:
BODY-CHECK-DEMO, not a sentence that merely contains that text.# are ignored.WARN is the safe rollout action. It records a match and keeps inspecting the message. It does not reject or discard mail.Recovery: The shell command changes a configuration file. To undo it, remove the added rule or restore your saved copy before reloading Postfix.
Use postmap with standard input to ask the configured map what it returns:
$ postmap -q - pcre:/etc/postfix/body_checks.pcre <<'EOF'
BODY-CHECK-DEMO
EOF
WARN body_checks demo marker matched
$ postmap -q - pcre:/etc/postfix/body_checks.pcre <<'EOF'
an ordinary line
EOF
The first query prints the action. The second prints nothing and returns a non-zero status, because no pattern matched. Capture the status immediately if a script needs it:
$ postmap -q - pcre:/etc/postfix/body_checks.pcre <<'EOF'
an ordinary line
EOF
$ printf 'query status: %s\n' "$?"
query status: 1
This checks lookup behaviour, not the complete SMTP path. It does not prove that a message will reach the cleanup service, or that a downstream Milter will behave the same way.
Only after the query behaves as expected, set the parameter with elevated privileges:
# sudo postconf -e 'body_checks = pcre:/etc/postfix/body_checks.pcre'
# postconf -h body_checks
pcre:/etc/postfix/body_checks.pcre
Check the configuration, then reload:
# sudo postfix check
# sudo postfix reload
Warning: These commands can affect mail processing, although this particular rule only logs. If postfix check reports an error, do not reload.
Recovery: Undo the setting with sudo postconf -X body_checks if the parameter was newly added, or restore its previous value with sudo postconf -e 'body_checks = PREVIOUS_VALUE'. Replace PREVIOUS_VALUE with the value you saved in step 1, and do not type the placeholder literally.
Submit a harmless test message through the normal local submission path, with the marker on its own line. This may queue mail, so use a test recipient and follow your site's mail-handling policy:
$ /usr/sbin/sendmail -t <<'EOF'
From: [email protected]
To: [email protected]
Subject: body_checks test
BODY-CHECK-DEMO
EOF
Look in the Postfix log for the text from the WARN action. On systemd systems, a common read-only check is:
$ sudo journalctl -u postfix --since '5 minutes ago' --no-pager | grep 'body_checks demo marker matched'
Log locations vary, and a missing line can mean the message used a different Postfix instance or submission path. Check the queue and service logs before changing the pattern.
When the observation is right, replace WARN with the action your policy needs:
REJECT stops the whole message and affects all recipients.DISCARD claims successful delivery, then silently drops the message.HOLD keeps the message in the hold queue until someone releases or deletes it.Warning: These are operational and security-sensitive decisions. Keep the working WARN version so you can revert quickly.
$line_length_limit bytes, and a decision about one line is not carried into the next. A phrase split across two lines does not match a single-line pattern.body_checks_size_limit limits how much content per message body segment is inspected. Check it with postconf body_checks_size_limit if large attachments matter. A rule that covers a small test message does not necessarily cover every byte of a large attachment.postconf -m listed the type you selected.postmap -q returned the expected action for a matching line and nothing for a non-matching one.postfix check passed before the reload.