- Go 94%
- Makefile 5.1%
- Dockerfile 0.9%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| cmd | ||
| examples | ||
| internal | ||
| Dockerfile | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| Makefile | ||
| README.md | ||
Postgrey Go
A Go implementation of Postgrey, a Postfix greylisting policy server.
Overview
Postgrey is a Postfix policy server implementing greylisting. When a request for delivery of a mail is received by Postfix via SMTP, the triplet CLIENT_IP / SENDER / RECIPIENT is built. If it is the first time that this triplet is seen, or if the triplet was first seen less than the configured delay time ago, then a temporary rejection is returned. The client is expected to retry after some time, as RFC 2821 indicates. It is expected that spammers don't retry, so they get effectively rejected.
This is a complete rewrite of the original Perl Postgrey in Go, providing better performance, memory efficiency, and easier deployment.
Features
- Greylisting: Temporary rejection of unknown sender/recipient combinations
- Whitelist support: Client and recipient whitelists with multiple formats
- Auto-whitelisting: Automatic whitelisting of clients after successful deliveries
- Database storage: BadgerDB or SQLite-based storage (replacing BerkeleyDB)
- Network protocols: Support for Unix domain sockets and TCP
- Logging: Comprehensive logging with syslog support
- Signal handling: Graceful shutdown and configuration reload
- Privacy mode: Hash-based key storage for privacy
- Maintenance: Automatic cleanup of old entries
Installation
From Source
git clone https://github.com/pugnos/postgrey
cd postgrey
go build -o postgrey ./cmd/postgrey
sudo cp postgrey /usr/local/bin/
Binary Installation
Download the latest release from the releases page and copy to your system:
sudo cp postgrey /usr/local/bin/
sudo chmod +x /usr/local/bin/postgrey
Configuration
Basic Setup
- Create a user for postgrey:
sudo useradd -r -s /bin/false -d /var/spool/postfix/postgrey postgrey
- Create the database directory:
sudo mkdir -p /var/spool/postfix/postgrey
sudo chown postgrey:postgrey /var/spool/postfix/postgrey
sudo chmod 755 /var/spool/postfix/postgrey
- Install whitelist files:
sudo cp examples/postgrey_whitelist_clients /etc/postfix/
sudo cp examples/postgrey_whitelist_recipients /etc/postfix/
- Configure Postfix by adding to
/etc/postfix/main.cf:
smtpd_recipient_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_destination,
check_policy_service inet:127.0.0.1:10023
- Start postgrey:
postgrey --inet=127.0.0.1:10023 --user=postgrey --daemonize
Command Line Options
Network Options
--unix=PATH: Unix domain socket path--inet=HOST:PORT: TCP address to bind to--socketmode=MODE: Unix socket permissions (octal)--connection-timeout=SECONDS: Connection timeout in seconds (default: 60)--read-timeout=SECONDS: Read timeout in seconds (default: 120)--write-timeout=SECONDS: Write timeout in seconds (default: 30)--max-connections=N: Maximum concurrent connections (default: 100)
Process Options
--user=USER: User to run as--group=GROUP: Group to run as--pidfile=PATH: PID file path--daemonize: Run as daemon
Greylisting Options
--delay=SECONDS: Greylist delay in seconds (default: 300)--max-age=DAYS: Maximum age of entries in days (default: 35)--retry-window=TIME: Retry window (e.g., '2d' or '48h', default: 2d)--lookup-by-subnet: Lookup by subnet (default)--lookup-by-host: Lookup by individual host--ipv4cidr=BITS: IPv4 CIDR mask for subnet lookups (default: 24)--ipv6cidr=BITS: IPv6 CIDR mask for subnet lookups (default: 64)--auto-whitelist-clients=N: Auto-whitelist after N successful attempts--privacy: Use privacy mode (hash keys)
Response Options
--greylist-action=ACTION: Action for greylisted mail (default: DEFER_IF_REJECT)--greylist-text=TEXT: Response text for greylisted mail--x-greylist-header=HEADER: Add header to passed mail
Whitelist Options
--whitelist-clients=FILE: Client whitelist files (can specify multiple)--whitelist-recipients=FILE: Recipient whitelist files (can specify multiple)
Logging Options
--verbose: Verbose logging--quiet: Quiet mode--syslog-facility=FACILITY: Syslog facility (default: mail)--hostname=NAME: Hostname for logging
Whitelist Formats
Client Whitelists
Client whitelists support the following formats:
- Hostnames:
example.com(matches*.example.comandexample.com) - IPv4 addresses:
192.168.1.1 - IPv4 networks:
192.168.1.0/24or192.168.1(implied /24) - IPv6 addresses:
2001:db8::1 - IPv6 networks:
2001:db8::/32 - Regular expressions:
/pattern/
Recipient Whitelists
Recipient whitelists support:
- Full addresses:
user@example.com(including extended addresses likeuser+tag@example.com) - Domain patterns:
example.com(matches all users at domain) - User patterns:
user@(matches user at any domain) - Regular expressions:
/pattern/
Systemd Service
Create /etc/systemd/system/postgrey.service:
[Unit]
Description=Postgrey Postfix Greylisting Service
Documentation=https://github.com/pugnos/postgrey
After=network.target postfix.service
Wants=postfix.service
[Service]
Type=notify
User=postgrey
Group=postgrey
ExecStart=/usr/local/bin/postgrey --inet=127.0.0.1:10023 --user=postgrey --pidfile=/var/run/postgrey.pid
ExecReload=/bin/kill -HUP $MAINPID
PIDFile=/var/run/postgrey.pid
Restart=always
RestartSec=5
# Security settings
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/spool/postfix/postgrey
[Install]
WantedBy=multi-user.target
Enable and start:
sudo systemctl daemon-reload
sudo systemctl enable postgrey
sudo systemctl start postgrey
Database
The Go version supports both BadgerDB (default) and SQLite for storage, replacing the original BerkeleyDB. The database is automatically created and managed.
Database Types
BadgerDB (Recommended)
- High-performance embedded key-value store
- Built-in TTL (Time To Live) support for automatic cleanup
- Better memory efficiency and concurrent access
- Native Go implementation with excellent performance
SQLite
- Traditional SQL database for compatibility
- Familiar query capabilities
- Slightly larger memory footprint
- Good for debugging and data inspection
Database Location
BadgerDB: By default, the database is stored in /var/spool/postfix/postgrey/greylist.badger/
SQLite: By default, the database is stored in /var/spool/postfix/postgrey/greylist.db
You can change the directory with the --dbdir option and select the database type with --db-type.
Choosing a Database Type
# Use BadgerDB (default, recommended)
postgrey --inet=127.0.0.1:10023 --db-type=badger
# Use SQLite for compatibility
postgrey --inet=127.0.0.1:10023 --db-type=sqlite
Maintenance
BadgerDB:
- Automatic TTL-based cleanup (no manual maintenance needed)
- Built-in garbage collection for optimal performance
- Background compaction and cleanup
SQLite:
- Old entries are cleaned up based on
--max-agesetting - Maintenance runs every hour
- Manual maintenance is triggered on SIGHUP
Monitoring
Log Files
Postgrey logs to syslog by default. Check your system logs:
# On systems with journald
journalctl -u postgrey -f
# On systems with traditional syslog
tail -f /var/log/mail.log | grep postgrey
Statistics
Postgrey logs statistics about whitelist entries and policy decisions. Look for entries like:
postgrey: Loaded whitelists: 45 clients, 23 recipients, 8 IPs
postgrey: action=DEFER_IF_REJECT, reason=new, client=unknown[192.168.1.100], sender=spam@example.com, recipient=user@domain.com
postgrey: action=OK, reason=pass, client=mail.google.com[172.217.1.26], sender=user@gmail.com, recipient=user@domain.com, age=315.2s
Migration from Perl Version
To migrate from the original Perl Postgrey:
- Stop the old Postgrey service
- Install the Go version
- Copy your existing whitelist files (they're compatible)
- The database will be recreated automatically (old greylisting state will be lost)
- Choose your database type (
--db-type=badgerrecommended for best performance) - Update your service configuration
- Start the new service
Troubleshooting
Common Issues
Permission denied accessing database
sudo chown -R postgrey:postgrey /var/spool/postfix/postgrey
Socket permission errors
# For Unix sockets, ensure proper permissions
postgrey --unix=/var/spool/postfix/postgrey/socket --socketmode=666
Connection timeout issues
# Increase timeouts for slow networks
postgrey --inet=127.0.0.1:10023 --read-timeout=180 --write-timeout=60
# Test connection health
postgrey-test --addr=127.0.0.1:10023 --verbose
Too many connections
# Increase connection limit
postgrey --inet=127.0.0.1:10023 --max-connections=200
Postfix connection refused
# Check if postgrey is running
systemctl status postgrey
# Check if port is listening
netstat -ln | grep 10023
# Test connectivity
postgrey-test --addr=127.0.0.1:10023
Debug Mode
Run with verbose logging to debug issues:
postgrey --inet=127.0.0.1:10023 --verbose
Use the connection test tool to verify connectivity:
postgrey-test --addr=127.0.0.1:10023 --verbose --timeout=30
Contributing
Contributions are welcome! Please submit pull requests or issues on GitHub.
License
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
Credits
- Original Postgrey by David Schweikert
- Go implementation by Nils Olofsson
- Based on the greylisting concept by Evan Harris