Server — Mail — Pyzor

Posted on 9 2026

Pyzor is a collaborative spam detection network that operates on the same principle as Razor: it computes a hash of each message’s body and queries a distributed server to see whether that hash has been reported as spam. The two networks are independent and draw from different pools of reporters, so running both increases coverage. A spam campaign that slips past Razor may be caught by Pyzor, and vice versa.

The architecture is simpler than Razor: Pyzor has one public server at public.pyzor.org, uses UDP rather than TCP, and does not require account registration. It is entirely free with no usage restrictions.

The Python 3 situation

This is worth knowing before installing anything. The officially released Pyzor package, version 1.0.0, has a known incompatibility with Python 3.x. Ubuntu 24.04 ships Python 3.12, which means the pyzor package from the Ubuntu repository will install but may not function correctly when called by SpamAssassin.

The fix exists in Pyzor’s GitHub repository but has not been cut into a formal release. There are two paths:

Option one: Ubuntu package with pipx fallback. Install the Ubuntu package and test it. If it works, great. If SpamAssassin’s debug output shows Pyzor failing to get a response, switch to option two.

Option two: install from GitHub via pipx. Install the patched version directly from the SpamExperts fork on GitHub, which keeps the Python 3 fixes current. This is the more reliable path on Ubuntu 24.04.

This article covers option two as the primary approach, since it is more likely to work on a fresh Ubuntu 24.04 installation. Option one is a one-liner and worth trying first if you prefer to stay within the package manager.

Option one: Ubuntu package

sudo apt install pyzor

Test it immediately:

sudo -u spamd pyzor ping

A working Pyzor returns a response like public.pyzor.org:24441 (200, 'OK') 0 0. If it returns an error about Python compatibility or no response at all, move to option two.

Option two: install from GitHub via pipx

Install pipx if it is not already present:

sudo apt install pipx
sudo pipx ensurepath

Install the patched Pyzor from the SpamExperts fork:

sudo pipx install   https://github.com/SpamExperts/pyzor/archive/refs/heads/master.zip   --global

The --global flag installs into /usr/local/bin so it is accessible system-wide rather than only for the current user. Confirm the binary is available:

which pyzor
pyzor --version

Firewall

Pyzor communicates with its server over UDP port 24441. February’s UFW configuration allows all outbound connections by default, so no changes are needed. If outbound UDP is restricted:

sudo ufw allow out 24441/udp

Creating the Pyzor home directory

Like Razor, Pyzor stores its configuration in a home directory owned by the SpamAssassin user:

sudo mkdir -p /var/lib/spamassassin/.pyzor
sudo chown -R spamd:spamd /var/lib/spamassassin/.pyzor

Server discovery

Pyzor needs a servers file telling it where public.pyzor.org resolves. The old pyzor discover command was discontinued years ago. Instead, create the servers file manually:

echo "public.pyzor.org:24441" | sudo -u spamd tee   /var/lib/spamassassin/.pyzor/servers > /dev/null

Confirm the file contents:

cat /var/lib/spamassassin/.pyzor/servers

It should contain exactly one line: public.pyzor.org:24441.

Testing the connection

Verify Pyzor can reach the public server:

sudo -u spamd pyzor --homedir /var/lib/spamassassin/.pyzor ping

A successful response looks like:

public.pyzor.org:24441  (200, 'OK')  0  0

A timeout or connection refused means either the server is temporarily unavailable, UDP port 24441 is blocked, or the servers file is not being read. Check the path and ownership of the .pyzor directory if the servers file is correct but Pyzor is not finding it.

Enabling Pyzor in SpamAssassin

Uncomment the plugin

Find and uncomment the Pyzor plugin line in /etc/spamassassin/v310.pre (check which .pre file exists on your installation):

# Before:
# loadplugin Mail::SpamAssassin::Plugin::Pyzor

# After:
loadplugin Mail::SpamAssassin::Plugin::Pyzor

Configure the plugin

Add Pyzor configuration to /etc/spamassassin/local.cf:

# Pyzor configuration
use_pyzor           1
pyzor_path          /usr/local/bin/pyzor
pyzor_options       --homedir /var/lib/spamassassin/.pyzor
pyzor_timeout       10
pyzor_max           5

# Pyzor scoring
score PYZOR_CHECK   2.5

pyzor_path points to the Pyzor binary. The path /usr/local/bin/pyzor is correct for the pipx global installation. If you installed from the Ubuntu package, use /usr/bin/pyzor instead. Confirm the actual path with which pyzor.

pyzor_options --homedir tells Pyzor where its home directory is. Without this, Pyzor looks in the default location, which may not be readable by the spamd user.

pyzor_timeout 10 sets the maximum wait time. The default is 3.5 seconds, which can be tight if the public server is slow. Ten seconds gives more breathing room without significantly delaying mail processing.

pyzor_max 5 sets how many times a message’s hash must have been reported before SpamAssassin considers the Pyzor check a match. The default is 5, which is conservative enough to avoid false positives from coincidental hash collisions.

score PYZOR_CHECK 2.5 adds 2.5 points to the SpamAssassin score when Pyzor identifies the message. Combined with Razor’s scoring, a message hit by both networks accumulates enough points to be tagged as spam on collaborative filtering alone.

Restarting SpamAssassin

sudo systemctl restart spamd

Check the service started cleanly:

sudo systemctl status spamd
sudo journalctl -u spamd -n 20

Testing

Verify SpamAssassin can load the Pyzor plugin:

sudo -u spamd spamassassin --lint 2>&1 | grep -i pyzor

A clean result shows no errors. Any failed or error lines need investigating before Pyzor will work.

Test with SpamAssassin’s sample spam file:

sudo -u spamd spamassassin -t -D pyzor   < /usr/share/doc/spamassassin/sample-spam.txt 2>&1 | grep -i pyzor

Watch for lines like:

pyzor: pyzor is available: /usr/local/bin/pyzor
pyzor: got response: public.pyzor.org:24441 (200, 'OK') 0 0

The (200, 'OK') confirms the server responded. The trailing numbers are the reported count and whitelisted count for the specific message hash. A zero reported count on the sample file is normal; it means that specific message is not in Pyzor’s database, which is expected for a sample file that has been in circulation for years.

To test with a real spam message you have received:

sudo -u spamd spamassassin -t -D pyzor < /path/to/spam.eml 2>&1 | grep -i pyzor

A high reported count on a real spam message confirms Pyzor is querying correctly and the message is known to the network.

Pyzor versus Razor: the practical difference

Both check message hashes against collaborative databases. The differences are operational rather than conceptual.

Razor uses TCP, requires registration, and has a reputation system that weights reports by the trust level of the reporter. Pyzor uses UDP, requires no registration, and is fully free without capacity constraints. Razor’s reputation system makes it somewhat more resistant to hash poisoning, where spammers try to flood the database with incorrect reports. Pyzor’s simplicity makes it easier to operate and maintain.

In practice, the two networks have different coverage. Some spam campaigns are in Razor’s database but not Pyzor’s, and vice versa. Running both with conservative individual scores rather than a high score on either one provides better coverage with lower false positive risk than relying heavily on either alone.

Log entries to recognise

Pyzor activity appears in the SpamAssassin log as:

pyzor: got response: public.pyzor.org:24441 (200, 'OK') 15 0

The third number is the reported count for the message hash. A count above your pyzor_max setting triggers the PYZOR_CHECK rule. A count of zero means the message is not in Pyzor’s database. A timeout or connection error means Pyzor could not reach the server and the check was skipped.