A lightweight, bash-based Prometheus exporter for Postfix mail server statistics. This exporter uses only bash and socat to provide comprehensive Postfix metrics for monitoring with Prometheus and Grafana.
- Pure Bash Implementation: No external dependencies except
socat - Comprehensive Metrics: Exports Postfix statistics including:
- Queue sizes (active, deferred, incoming, hold, maildrop, corrupt)
- Message counters (received, delivered, forwarded, deferred, bounced, rejected)
- SMTP connection statistics and SASL authentication
- Rejection reasons (RBL, HELO, sender, recipient, client, unknown user)
- Delivery status by transport (smtp, lmtp, virtual, pipe)
- Process status and uptime
- Postfix version information
- Stateful Counter Tracking: Maintains persistent counters for accurate Prometheus rate calculations
- HTTP Server: Built-in HTTP server using socat for serving metrics
- Systemd Integration: Ready-to-use systemd service file
- Grafana Dashboard: Pre-built comprehensive dashboard
- Multi-Instance Support: Monitor multiple Postfix servers
- Postfix mail server
socatpackage installed- Prometheus server for scraping metrics
- Read access to Postfix logs and queue directory
- Clone the repository:
git clone https://github.com/itefixnet/prometheus-postfix-exporter.git
cd prometheus-postfix-exporter- Make scripts executable:
chmod +x *.sh- Test the exporter:
sudo ./postfix-exporter.sh test- Start the HTTP server:
sudo ./http-server.sh start- Access metrics at
http://localhost:9154/metrics
For production deployment, install as a system service:
# Create user and directories
sudo useradd -r -s /bin/false postfix-exporter
sudo mkdir -p /opt/postfix-exporter
sudo mkdir -p /var/lib/postfix-exporter
# Copy files
sudo cp *.sh /opt/postfix-exporter/
sudo cp config.sh /opt/postfix-exporter/
sudo cp postfix-exporter.conf /opt/postfix-exporter/
sudo cp postfix-exporter.service /etc/systemd/system/
# Set permissions
sudo chown -R postfix-exporter:postfix-exporter /opt/postfix-exporter
sudo chown -R postfix-exporter:postfix-exporter /var/lib/postfix-exporter
sudo chmod +x /opt/postfix-exporter/*.sh
# Add user to adm group for log access
sudo usermod -a -G adm postfix-exporter
# Enable and start service
sudo systemctl daemon-reload
sudo systemctl enable postfix-exporter
sudo systemctl start postfix-exporter
# Check status
sudo systemctl status postfix-exporterThe exporter can be configured using environment variables or configuration files:
| Variable | Default | Description |
|---|---|---|
POSTFIX_LOG |
/var/log/mail.log |
Path to Postfix log file |
POSTFIX_QUEUE_DIR |
/var/spool/postfix |
Path to Postfix queue directory |
LISTEN_PORT |
9154 |
HTTP server port |
LISTEN_ADDRESS |
0.0.0.0 |
HTTP server bind address |
METRICS_PREFIX |
postfix |
Prometheus metrics prefix |
LOG_LINES |
10000 |
Number of log lines to parse on first run |
STATE_FILE |
/var/lib/postfix-exporter/state |
State file for persistent counters |
MAX_CONNECTIONS |
10 |
Maximum concurrent HTTP connections |
TIMEOUT |
30 |
Request timeout in seconds |
How it works: The exporter maintains persistent counters in a state file, tracking the log file position (inode and byte offset). On each scrape, it:
- Reads only new log entries since the last position
- Parses all metrics (messages, SMTP connections, rejections, deliveries) in a single pass
- Increments the appropriate counters in memory
- Saves the updated state (counters and position) to disk
This architecture ensures counters monotonically increase as required by Prometheus, enabling accurate rate() and increase() calculations. Log rotation and truncation are automatically detected and handled. All log parsing is consolidated in the parse_log_direct() function to prevent position conflicts and ensure data consistency.
config.sh: Shell configuration file (sourced by scripts)postfix-exporter.conf: Systemd environment file
The exporter provides comprehensive Postfix mail server metrics:
postfix_master_process_running- Postfix master process status (1=running, 0=not running)postfix_master_process_uptime_seconds- Postfix master process uptime in seconds (counter)postfix_version_info{version="..."}- Postfix version information with label
postfix_queue_size{queue="incoming"}- Number of messages in incoming queuepostfix_queue_size{queue="maildrop"}- Number of messages in maildrop queuepostfix_queue_size{queue="active"}- Number of messages in active queuepostfix_queue_size{queue="deferred"}- Number of messages in deferred queuepostfix_queue_size{queue="hold"}- Number of messages in hold queuepostfix_queue_size{queue="corrupt"}- Number of messages in corrupt queue
postfix_messages_received_total- Total number of messages received (counter)postfix_messages_delivered_total- Total number of messages delivered (counter)postfix_messages_forwarded_total- Total number of messages forwarded (counter)postfix_messages_deferred_total- Total number of messages deferred (counter)postfix_messages_bounced_total- Total number of messages bounced (counter)postfix_messages_rejected_total- Total number of messages rejected (counter)
postfix_smtpd_connections_total- Total SMTP connections (counter)postfix_smtpd_noqueue_total- Total NOQUEUE rejections (counter)postfix_smtpd_sasl_authenticated_total- Total SASL authenticated sessions (counter)postfix_smtpd_sasl_failed_total- Total SASL authentication failures (counter)
postfix_smtpd_reject_total{reason="rbl"}- SMTP rejections due to RBL (counter)postfix_smtpd_reject_total{reason="helo"}- SMTP rejections due to HELO (counter)postfix_smtpd_reject_total{reason="sender"}- SMTP rejections due to sender (counter)postfix_smtpd_reject_total{reason="recipient"}- SMTP rejections due to recipient (counter)postfix_smtpd_reject_total{reason="client"}- SMTP rejections due to client (counter)postfix_smtpd_reject_total{reason="unknown_user"}- SMTP rejections due to unknown user (counter)
postfix_delivery_status_total{transport="smtp",status="sent"}- Deliveries via SMTP (counter)postfix_delivery_status_total{transport="lmtp",status="sent"}- Deliveries via LMTP (counter)postfix_delivery_status_total{transport="virtual",status="sent"}- Deliveries via virtual transport (counter)postfix_delivery_status_total{transport="pipe",status="sent"}- Deliveries via pipe transport (counter)
# Test connection to Postfix
sudo ./postfix-exporter.sh test
# Collect metrics once
sudo ./postfix-exporter.sh collect
# Start HTTP server manually
sudo ./http-server.sh start
# Test HTTP endpoints
curl http://localhost:9154/metrics
curl http://localhost:9154/health
curl http://localhost:9154/Add jobs to your prometheus.yml for single or multiple Postfix instances:
scrape_configs:
# Single instance
- job_name: 'postfix-exporter'
static_configs:
- targets: ['localhost:9154']
scrape_interval: 30s
metrics_path: /metrics
# Multiple instances with labels
- job_name: 'postfix-servers'
static_configs:
- targets: ['mail1.example.com:9154', 'mail2.example.com:9154']
labels:
environment: 'production'
datacenter: 'dc1'
- targets: ['staging.example.com:9154']
labels:
environment: 'staging'
datacenter: 'dc2'
scrape_interval: 30s
metrics_path: /metricsImport the provided grafana-dashboard.json file into your Grafana instance:
- Go to Dashboards → Import
- Upload
grafana-dashboard.jsonor copy/paste the JSON content - Configure Data Source: Select your Prometheus datasource from the dropdown
- Click "Import"
Troubleshooting Dashboard Import:
- If you get "data source was not found" error, ensure your Prometheus datasource is properly configured in Grafana
- Make sure your Prometheus is scraping the Postfix exporter endpoints
- Verify metrics are available by checking:
http://your-grafana/explore→ Select Prometheus → Querypostfix_master_process_running
Dashboard Features:
The comprehensive Grafana dashboard includes:
-
Overview Row:
- Message Rate panel (received, delivered, rejected, bounced per minute) - full width
-
Queue Details Row:
- Queue Size by Type (stacked area chart showing active, deferred, incoming, hold, maildrop)
- Current Queue Sizes (bar gauge with color thresholds)
-
Message Statistics Row:
- Message Flow (1h increase) showing received, delivered, deferred, bounced
- Message Distribution (24h pie chart with percentages)
-
SMTP & Rejections Row (collapsed by default):
- SMTP Connections per minute (connections, SASL authenticated, SASL failed)
- SMTP Rejections by Reason per minute (stacked chart by reason: RBL, HELO, sender, recipient, client, unknown user)
-
Delivery Details Row (collapsed by default):
- Deliveries by Transport per minute (smtp, lmtp, virtual, pipe)
All panels support:
- Multi-instance filtering with template variables
- Auto-refresh (30 second default)
- Time range selection
- Drill-down capabilities
Multi-Instance Support: The dashboard includes template variables for monitoring multiple Postfix instances:
- Instance: Filter by specific instance (e.g.,
mail1.example.com:9154,localhost:9154) - Job: Filter by Prometheus job name
To monitor multiple instances, configure your prometheus.yml as shown above.
The dashboard supports:
- Multi-Instance Monitoring: Automatically discovers all Postfix exporters
- Flexible Filtering: Filter by instance (host:port) and job name
- Multi-Select Variables: Monitor multiple instances simultaneously
- Instance Labeling: All metrics show which instance they come from
-
Permission Denied:
- Ensure scripts are executable:
chmod +x *.sh - Add exporter user to
admgroup for log access:sudo usermod -a -G adm postfix-exporter - Check queue directory permissions
- Ensure scripts are executable:
-
Cannot Read Log File:
- Verify log file path:
ls -la /var/log/mail.log - Check user permissions:
sudo -u postfix-exporter cat /var/log/mail.log - Ensure log file exists and is readable
- Verify log file path:
-
Port Already in Use:
- Change
LISTEN_PORTin configuration - Check for other services:
netstat -tlnp | grep 9154
- Change
-
Missing Dependencies:
# Install socat (Ubuntu/Debian) sudo apt-get install socat # Install socat (CentOS/RHEL) sudo yum install socat
-
Postfix Not Detected:
- Verify Postfix is running:
systemctl status postfix - Check queue directory:
ls -la /var/spool/postfix - Ensure postconf is available:
which postconf
- Verify Postfix is running:
- Service logs:
journalctl -u postfix-exporter -f - Manual logs: Scripts output to stderr
For high-traffic mail servers:
- Adjust
LOG_LINESto analyze fewer lines (faster but less accurate) - Consider running exporter on a separate monitoring server
- Monitor system resources
- Tune scrape interval in Prometheus
# Run basic tests
sudo ./postfix-exporter.sh test
sudo ./http-server.sh test
# Test with different configurations
POSTFIX_LOG=/var/log/maillog sudo ./postfix-exporter.sh test- Fork the repository
- Create a feature branch
- Test thoroughly
- Submit a pull request
This project is licensed under the BSD 2-Clause License - see the LICENSE file for details.
- GitHub Issues: https://github.com/itefixnet/prometheus-postfix-exporter/issues
- Documentation: This README and inline script comments
This exporter focuses on simplicity and minimal dependencies. For more advanced features, consider:
- postfix_exporter (Go-based)
- Custom telegraf configurations
- Native Prometheus monitoring solutions
Inspired by the prometheus-apache2-exporter project.
- prometheus-apache2-exporter - Apache HTTP server exporter
