Home / Alt manpages / body_checks(5)

  • body_checks(5)
  • File format
  • linux

Test Postfix body_checks Rules Before They Reject Mail

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.

  • You need: shell access, the Postfix package, and an account that can read the configuration.
  • Privileges: editing /etc/postfix and reloading Postfix need elevated privileges.
  • What it avoids: the examples stay clear of REJECT, DISCARD and HOLD until the rule has been checked.

1. Check lookup-table support

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.

2. Create a rule that only logs

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:

  • Anchored at both ends. It matches a physical body line whose complete content is BODY-CHECK-DEMO, not a sentence that merely contains that text.
  • Comments and blanks. Blank lines and lines beginning with # are ignored.
  • File order. Rules are tried in order, and a matching action is applied before Postfix moves to the next input line.
  • 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.

3. Query the rule without sending mail

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.

4. Connect the table to Postfix

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.

5. Watch a real match, then pick an action

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.

6. Know the limits that cause surprises

  • One physical line at a time. A body rule sees chunks no longer than $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.
  • No decoding. Postfix does not decode attachments or unzip archives for these checks. Encoded body text must be matched in its encoded form, so a base64 attachment is not presented as its decoded filename or contents.
  • Headers are separate. Header rules are a different facility, and MIME headers are not the same input as ordinary body lines.
  • Size limit. 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.

Done means

  • Table type confirmed. postconf -m listed the type you selected.
  • Query behaves. postmap -q returned the expected action for a matching line and nothing for a non-matching one.
  • Config checked. postfix check passed before the reload.
  • Real match seen. A controlled test message produced the expected log entry.
  • Action reversible. The final action is deliberate, documented and reversible from the saved configuration.