My implementation of postgrey.
  • Go 94%
  • Makefile 5.1%
  • Dockerfile 0.9%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2025-12-09 22:31:27 +00:00
cmd updating version strings 2025-12-09 22:31:27 +00:00
examples Initial public verion 2025-12-09 18:21:03 +00:00
internal updating version strings 2025-12-09 22:31:27 +00:00
Dockerfile Initial public verion 2025-12-09 18:21:03 +00:00
go.mod Initial public verion 2025-12-09 18:21:03 +00:00
go.sum Initial public verion 2025-12-09 18:21:03 +00:00
LICENSE Initial public verion 2025-12-09 18:21:03 +00:00
Makefile updating version strings 2025-12-09 22:31:27 +00:00
README.md Initial public verion 2025-12-09 18:21:03 +00:00

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

  1. Create a user for postgrey:
sudo useradd -r -s /bin/false -d /var/spool/postfix/postgrey postgrey
  1. 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
  1. Install whitelist files:
sudo cp examples/postgrey_whitelist_clients /etc/postfix/
sudo cp examples/postgrey_whitelist_recipients /etc/postfix/
  1. 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
  1. 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.com and example.com)
  • IPv4 addresses: 192.168.1.1
  • IPv4 networks: 192.168.1.0/24 or 192.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 like user+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-age setting
  • 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:

  1. Stop the old Postgrey service
  2. Install the Go version
  3. Copy your existing whitelist files (they're compatible)
  4. The database will be recreated automatically (old greylisting state will be lost)
  5. Choose your database type (--db-type=badger recommended for best performance)
  6. Update your service configuration
  7. 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

See Also