Skip to content

Commit d1c0926

Browse files
committed
Complete structural and conceptual redesign. See CHANGELOG.md for full details.
1 parent 4082fd5 commit d1c0926

12 files changed

+572
-177
lines changed

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
config.xml
2-
+config.xml.sample
1+
postfix-bounce-report.conf
2+
+postfix-bounce-report.conf.example

CHANGELOG.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Changelog
2+
3+
## [2025-07-11] Improved Version
4+
5+
### Changed
6+
7+
- Switched configuration format from `.xml` to `.conf` (bash-compatible).
8+
- Replaced unstructured `MAILINFO` HTML string concatenation with structured `$'\n'`-based formatting for better readability.
9+
- Improved line breaks and indentation in HTML email output.
10+
- Replaced hardcoded HTML with external template system.
11+
- Improved internal date parsing.
12+
13+
### Added
14+
15+
- Introduced `html_escape()` function to properly escape special characters in HTML output.
16+
- Added runtime duration output in the final report.
17+
- Included command-line debug messages (`[INFO]`, `[CRITICAL]`) for better traceability.
18+
- Add `ONELINE` option to disable line wrapping and enable horizontal scrolling in HTML table output
19+
- Separated CSS into external template files for cleaner HTML and easier customization.
20+
- Enabled usage of custom HTML and CSS templates via configuration (TEMPLATE_BASENAME).
21+
- Added fallback to default templates if custom templates are missing.
22+
- Updated script to dynamically load and embed CSS from external files into the email HTML.
23+
- Implemented example log entries in anonymized form for documentation/testing purposes.
24+
25+
### Updated
26+
27+
- Reworked and structured `README.md` instructions for better readability.
28+
- General code cleanup and structural improvements for maintainability.
29+
- Updated script shebang and ensured POSIX compatibility.

README.md

Lines changed: 172 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,201 @@
1-
# postfix-bounce-report
2-
The script generates an HTML report based on rejected messages. Another script continuously writes "recipient addresses" into a list. If an incoming message is rejected and is present in the list of "recipients", the subject of email is changing.
1+
![Postfix Compatible](https://img.shields.io/badge/Postfix-compatible-green)
2+
![Perl interpreter](https://img.shields.io/badge/Perl-required-orange)
3+
4+
# Postfix Bounce Report
5+
6+
<img src="images/logo-postfix-bounce-report.png" alt="Logo" width="30%" align="right" hspace="30" vspace="20"/>
7+
This script generates an HTML report based on rejected messages. Another script continuously writes "recipient addresses" to a list. If an incoming message is rejected and the recipient is present in the list, the subject of the email is adjusted.
38

49
<!-- TOC -->
510

6-
- [postfix-bounce-report](#postfix-bounce-report)
7-
- [FEATURES](#features)
8-
- [EXAMPLE](#example)
9-
- [HOW TO INSTALL](#how-to-install)
10-
- [PREREQUISITES PERL INTERPRETER AND XML EXTENSION](#prerequisites-perl-interpreter-and-xml-extension)
11-
- [CLONE REPOSITORY](#clone-repository)
12-
- [HOW TO USE](#how-to-use)
13-
- [CONFIGURATION](#configuration)
14-
- [CREATE SCHEDULED TASKS](#create-scheduled-tasks)
15-
- [ADDITIONAL INFORMATION](#additional-information)
16-
- [LICENSE](#license)
11+
- [Postfix Bounce Report](#postfix-bounce-report)
12+
- [Features](#features)
13+
- [Example](#example)
14+
- [Installation](#installation)
15+
- [Install Perl (Required Dependency)](#install-perl-required-dependency)
16+
- [Red Hat-based distributions (RHEL, CentOS, AlmaLinux, Rocky, Fedora)](#red-hat-based-distributions-rhel-centos-almalinux-rocky-fedora)
17+
- [Debian-based distributions (Ubuntu, Debian, etc.)](#debian-based-distributions-ubuntu-debian-etc)
18+
- [Check Perl version:](#check-perl-version)
19+
- [Clone the Repository](#clone-the-repository)
20+
- [Configuration](#configuration)
21+
- [Configuration via `.conf` File](#configuration-via-conf-file)
22+
- [Scheduled Execution (Cron)](#scheduled-execution-cron)
23+
- [Option A: User Crontab (crontab -e)](#option-a-user-crontab-crontab--e)
24+
- [Option B: System-wide Cron File (/etc/crontab)](#option-b-system-wide-cron-file-etccrontab)
25+
- [Log Rotation Compatibility](#log-rotation-compatibility)
26+
- [Contributions](#contributions)
27+
- [License](#license)
1728

1829
<!-- /TOC -->
1930

20-
## FEATURES
21-
- build_submission_recipients.sh : Analyzes the postfix maillog for outgoing e-mails and continuously creates a list of recipients
22-
- postfix-bounce-report.sh : Analyzes the postfix logfile for bounced emails by DDNS blacklist, optionaly validate/cross check FROM-value against submission list. Script also generates HTML report and send via sendmail
23-
- The subject is regular "[INFO] Postfix Bounce Report", a threshold value can be parameterized where the subject is changed to [WARNING]. For a match with the submission recipients list a [CRITIAL] is created
24-
- Since a spoofed e-mail address would lead to a CRITICAL, the definition of toplevel domains has been implemented in version 1.1.2. Spoofed addresses are thus recognized and marked accordingly in the HTML report.
31+
## Features
32+
33+
- `build_submission_recipients.sh`: Analyzes the Postfix mail log for outgoing emails and continuously creates a recipient list.
34+
- `postfix-bounce-report.sh`: Analyzes the Postfix log file for bounced emails due to DDNS blacklist, optionally validates/matches the FROM value with the submission list. The script also generates an HTML report and sends it via sendmail.
35+
- The default subject is "[INFO] Postfix Bounce Report". A threshold can be set to change the subject to [WARNING]. If there is a match with the submission recipient list, [CRITICAL] is set.
36+
37+
> ⚠️ **Important Notice**
38+
> This script has undergone **significant changes** in the latest version (2025-07-11).
39+
> If you have used a previous version, please consult the updated [CHANGELOG.md](./CHANGELOG.md) before upgrading.
40+
> Existing setups may require adaptation to the new format and template handling.
41+
42+
## Example
43+
44+
The following screenshot shows a **sample HTML report** generated by the script.
45+
All personal or sensitive data has been **anonymized** for demonstration purposes.
46+
47+
This example illustrates the typical layout, formatting, and information structure included in the bounce report email.
2548

26-
## EXAMPLE
2749
<img src="images/postfix-bounce-report-html-example.png" alt="Postfix Bounce Report HTML Example" width="100%"/>
2850

29-
## HOW TO INSTALL
51+
## Installation
52+
53+
### Install Perl (Required Dependency)
54+
55+
The script relies on basic Perl tools like `perl` or `perl-compatible regular expressions (PCRE)`. These are not always pre-installed, especially on minimal or container-based systems.
3056

31-
### PREREQUISITES PERL INTERPRETER AND XML EXTENSION
57+
#### Red Hat-based distributions (RHEL, CentOS, AlmaLinux, Rocky, Fedora)
3258

33-
Install XML library to read the XML files
34-
- Once System is fully updated, you can install libxml2-utils package through command:
35-
- RedHat-based: ```dnf install perl libxml2-utils```
36-
- Debian-based: ```apt install perl libxml2-utils```
59+
To install Perl:
3760

38-
Check Perl Version
39-
- Since the package is installed now, you can check the Perl version through ```perl -v``` command.
61+
```bash
62+
sudo dnf install perl
63+
```
4064

41-
### CLONE REPOSITORY
42-
Change to the root-directory of your linux-system: ```cd ~```
65+
On older systems, use yum instead of dnf.
4366

44-
Clone the repository to this directory: ```git clone https://github.com/filipnet/postfix-bounce-report.git```
45-
Afterwards you will find a new folder called "postfix-bounce-report" inside your root-directory
46-
To make the scripts universally applicable, some settings like email addresses are stored in a separate ```config.xml``` and must be adjusted here, the existing ```config.xml.sample``` renamed and adjusted before.
47-
Please note that the scripts must be made executable before the first use. ```chmod +x ~/*.sh```
67+
#### Debian-based distributions (Ubuntu, Debian, etc.)
4868

49-
## HOW TO USE
69+
To install Perl:
5070

51-
### CONFIGURATION
52-
Rename the file ```config.xml.sample``` to ```config.xml``` and adapt it to your system environment.
71+
```bash
72+
sudo apt update
73+
sudo apt install perl
5374
```
75+
76+
Most full Ubuntu/Debian installations already include Perl by default. Use the command above if not present.
77+
78+
#### Check Perl version:
79+
80+
- After installation, check the Perl version with `perl -v`.
81+
82+
### Clone the Repository
83+
84+
- Change to your home directory: `cd ~`
85+
- Clone the repository: `git clone https://github.com/filipnet/postfix-bounce-report.git`
86+
- A new folder "postfix-bounce-report" will appear in your home directory.
87+
- Make the scripts executable before first use: `chmod +x ~/*.sh`
88+
89+
## Configuration
90+
91+
> **Note:** Configuration is now done via a simple `.conf` file. The previous `config.xml.sample` is no longer used.
92+
93+
1. Rename the file `postfix-bounce-report.conf.example` to `postfix-bounce-report.conf`.
94+
2. Adjust the variables in this file to match your system environment.
95+
96+
```bash
5497
cd ~/postfix-bounce-report
55-
cp config.xml.sample config.xml
56-
vim/nano config.xml
98+
cp postfix-bounce-report.conf.example postfix-bounce-report.conf
99+
vim postfix-bounce-report.conf
100+
```
101+
102+
Using a `.conf` file eliminates the need for additional XML parser dependencies. The script can be run directly on a standard Linux system.
103+
104+
### Configuration via `.conf` File
105+
106+
The script reads its settings from a configuration file. Below is a list of supported options:
107+
108+
| Variable | Description | Example Value(s) |
109+
| -------------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------- |
110+
| `LC_ALL` | Locale setting for consistent date/time and string formatting during script execution. | `"de_DE.utf8"` |
111+
| `RED` | ANSI escape code for red terminal text. | `"\033[0;31m"` |
112+
| `GREEN` | ANSI escape code for green terminal text. | `"\033[0;32m"` |
113+
| `YELLOW` | ANSI escape code for yellow terminal text. | `"\033[0;33m"` |
114+
| `NC` | ANSI escape code to reset terminal color. | `"\033[0m"` |
115+
| `TEMPLATE_BASENAME` | Basename (without extension) of the HTML/CSS template files used for the report. | `"template.custom"` |
116+
| `MAILLOG` | Path to the Postfix mail log file to be analyzed. | `"/var/log/maillog"` |
117+
| `MAILLOG_PERIOD` | Time range in hours to scan for relevant log entries. | `"24"` |
118+
| `MAILLOG_PATTERN` | Regular expression to match relevant log lines (e.g. bounces or rejections). | `"blocked "` |
119+
| `LOGMAIL_FROM` | Email address used as sender of the bounce report. | `"do-not-reply@example.com"` |
120+
| `LOGMAIL_TO` | Email address of the recipient who will receive the report. | `"user@example.com"` |
121+
| `LOGMAIL_SUBJECT` | Subject line for the report email. | `"Postfix Bounce Report"` |
122+
| `RECIPIENTS_CHECK` | Enables verification of sender addresses against a known list when set to `true`. | `"true"` or `"false"` |
123+
| `RECIPIENTS_LIST` | Path to file with one valid recipient address per line. | `"/etc/postfix/submission_recipient"` |
124+
| `SEVERETY_THRESHOLD` | Numeric threshold to classify bounce severity (e.g. highlight known spoof attempts). | `"50"` |
125+
| `ONELINE` | Disables line wrapping and enables horizontal scrolling in the HTML report when set to `true`. | `"true"` or `"false"` |
126+
| `DOMAINS` | Pipe-separated list of trusted internal domains for spoof detection. | `"example.com"` |
127+
128+
## Scheduled Execution (Cron)
129+
130+
You can run the script automatically once per day using one of the two options below.
131+
132+
### Option A: User Crontab (crontab -e)
133+
134+
Run the script as a specific user (e.g., root):
135+
136+
```bash
137+
sudo crontab -e
138+
```
139+
140+
Add the following line:
141+
142+
```bash
143+
0 0 \* \* \* /root/postfix-bounce-report/postfix-bounce-report.sh > /dev/null 2>&1
144+
```
145+
146+
This executes the script every day at midnight.
147+
To log output for debugging, use:
148+
149+
```bash
150+
0 0 \* \* \* /root/postfix-bounce-report/postfix-bounce-report.sh >> /var/log/bounce-report.log 2>&1
151+
```
152+
153+
### Option B: System-wide Cron File (/etc/crontab)
154+
155+
Edit the system crontab file:
156+
157+
```bash
158+
sudo vim /etc/crontab
159+
```
160+
161+
Add the following line (note the required root user field):
162+
163+
```bash
164+
0 0 \* \* \* root /root/postfix-bounce-report/postfix-bounce-report.sh > /dev/null 2>&1
57165
```
58166

59-
### CREATE SCHEDULED TASKS
167+
This also executes the script daily at midnight.
60168

61-
Create a new file in ```/etc/cron.d/``` directory:
169+
### Log Rotation Compatibility
62170

63-
``` touch /etc/cron.d/postfix-bounce-report ```
171+
The script `postfix-bounce-report.sh` always analyzes log entries **from the previous calendar day** (`yesterday`) based on the system time.
172+
It uses tools like `date` and `grep` to extract matching lines from `/var/log/maillog` (or another specified log file).
64173

65-
The content should be:
174+
Make sure the following conditions are met:
66175

176+
- Your log rotation (e.g., via `logrotate`) **does not rotate the log file before midnight** if the bounce report is scheduled at `00:00`.
177+
- Rotated logs (e.g., `maillog.1`) are still **available and readable** when the script runs.
178+
- If your system compresses logs immediately (e.g., `.gz`), the script **will not find entries from yesterday** unless you extend it to support compressed files.
179+
180+
**Recommendation:**
181+
Schedule the bounce report script **shortly after midnight**, e.g., `00:05`, and ensure that log rotation (e.g., via `logrotate`) occurs **later**, e.g., `01:00`.
182+
183+
You can check the logrotate schedule via:
184+
185+
```bash
186+
cat /etc/cron.daily/logrotate
67187
```
68-
# https://github.com/filipnet/postfix-bounce-report
69-
# Hourly script that collects the recipients for the report
70-
@hourly root /root/postfix-bounce-report/postfix-build-submission-recipients.sh > /dev/null
71-
# Daily script that sens out the report as an e-mail
72-
@daily root /root/postfix-bounce-report/postfix-bounce-report.sh > /dev/null
188+
189+
Or if your system uses systemd timers:
190+
191+
```bash
192+
systemctl list-timers --all | grep logrotate
73193
```
74194

75-
Description
76-
- The script ```postfix-build-submission-recipients.sh``` scans the mail log every hour for sent e-mails, extracts the recipient's address and adds it to the list ```/etc/postfix/submission_recipients``` if not already present.
77-
- The script ```postfix-bounce-report.sh``` is executed once a day, returns as content an HTML table with cross-check to the submission list, sends it via e-mail.
195+
## Contributions
196+
197+
Contributions are welcome! If you would like to improve this project, please feel free to submit a pull request. All contributions, bug reports, and feature suggestions are appreciated.
78198

79-
## ADDITIONAL INFORMATION
80-
Please note that the script ```postfix-bounce-report.sh``` always generates the day before. Note if there are no conflict with your log-rotation jobs.
199+
## License
81200

82-
## LICENSE
83-
postfix-bounce-report and all individual scripts are under the BSD 3-Clause license unless explicitly noted otherwise. Please refer to the LICENSE
201+
postfix-bounce-report and all individual scripts are under the BSD 3-Clause license unless explicitly noted otherwise. See the [LICENSE](LICENSE) file for more details.

config.xml.sample

Lines changed: 0 additions & 13 deletions
This file was deleted.

0 commit comments

Comments
 (0)