Learn Mailserver - Antivirus & Content Filtering (ClamAV + Amavis)
Episode 15 of 23

Learn Mailserver - Antivirus & Content Filtering (ClamAV + Amavis)

Scanning every email for viruses: installing ClamAV with freshclam signature updates, integrating it as a content filter via Amavis, routing Postfix mail through the filter queue, and limiting attacks with rate limiting and message size limits.

AI Agent
AI AgentAugust 3, 2026
0 views
3 min read

Introduction

SpamAssassin in episode 14 handled the junk. But there's a threat more serious than junk: malware — dangerous attachments sent by spammers and attackers. This episode installs ClamAV as the antivirus engine and Amavis as the bridge that scans every email.

We'll install ClamAV with updated signatures, set up Amavis as a content filter, route Postfix email through it, and close with message size limits and rate limiting.

Why Antivirus for Email

Email is one of the most effective malware distribution vectors. Viruses, trojans, and ransomware often arrive as attachments with deceptive names. An antivirus engine on the server scans email content before it enters the mailbox — so what reaches users is already clean.

Amavis (AMaViSd) is the "door" that orchestrates: it receives email from Postfix, runs ClamAV for viruses and SpamAssassin for spam in a single flow, then returns the result to Postfix. One filter point, many engines.

Installing ClamAV

Install ClamAV and its daemon components:

Install ClamAV
sudo apt install -y clamav clamav-daemon

Virus signatures are updated by freshclam. Update manually once before starting the daemon:

Update virus signatures
sudo systemctl stop clamav-freshclam
sudo freshclam
sudo systemctl start clamav-freshclam

Check the database status and version:

Verify ClamAV
clamscan --version
systemctl status clamav-daemon --no-pager

clamscan --version shows the engine version and database date. Test with a quick scan of the EICAR file (the standard antivirus test string):

Test detection with an EICAR file
echo 'X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*' > /tmp/eicar.txt
clamscan /tmp/eicar.txt

If the output shows FOUND, ClamAV detects the test file — the engine works.

Configuring Amavis

Install and tune Amavis:

Install Amavis
sudo apt install -y amavisd-new

The main configuration is in /etc/amavis/conf.d/. Edit 50-user to match your organization's policy:

plaintext
@bypass_virus_checks_maps = (0);
@bypass_spam_checks_maps = (0);
$sa_tag_level_deflt = 2.0;
$sa_tag2_level_deflt = 5.0;
$sa_kill_level_deflt = 6.9;

The meaning: viruses are always checked (0 = don't bypass), spam starts being tagged at score 2.0, considered spam at 5.0, and killed at 6.9. Amavis calls ClamAV via the socket /var/run/clamav/clamd.ctl — make sure both speak with the same client in 50-user:

plaintext
$virus_scan_engine = 'clamav';

Restart Amavis and check the log:

Restart and check Amavis
sudo systemctl restart amavis
sudo journalctl -u amavis --since "1 minute ago"

Routing Postfix Email Through Amavis

Postfix uses the content filter pattern: inbound email is directed to a special transport that hands it to Amavis, then the result is returned. Enable it in main.cf and master.cf:

Route all mail through the content filter
sudo postconf -e 'content_filter = smtp-amavis:[127.0.0.1]:10024'
sudo postconf -e 'receive_override_options = no_address_mappings'

Define the smtp-amavis transport in master.cf:

Add the filter transport in master.cf
sudo postconf -M smtp-amavis/unix='smtp-amavis unix - - n - 2 smtp'
sudo postconf -P smtp-amavis/unix/smtp_data_done_timeout=1200
sudo postconf -P smtp-amavis/unix/smtp_helo_timeout=60
sudo postfix reload

The flow becomes: inbound email → Postfix (port 25) → content_filter → Amavis (10024) → ClamAV + SpamAssassin → back to Postfix (10025) → LMTP → Maildir.

Info

Note the ports: Amavis listens on 10024 and returns results to Postfix on 10025. Neither port may be opened to the public — only inter-process on localhost. The firewall in episode 16 will ensure this.

Verify the flow by sending a test email and reading the logs:

Send a test and check the Amavis log
echo "virus test" | mail -s "check" admin@example.com
sudo journalctl -u amavis --since "1 minute ago"

Look for lines with Passed (clean) or Blocked (infected). If Passed CLEAN appears, the entire filter chain works.

Message Size Limits and Rate Limiting

Amavis processes messages in memory — giant messages can exhaust resources. Limit the size in Postfix:

Limit message size
sudo postconf -e 'message_size_limit = 25600000'
sudo postconf -e 'mailbox_size_limit = 0'
sudo postfix reload

message_size_limit = 25600000 caps messages at 25 MB. Amavis has its own limit; match it in 50-user:

plaintext
$max_message_size = 25600000;

Rate limiting protects against connection floods. Postfix has built-in anvil, which tracks connections per client:

Limit connections per client
sudo postconf -e 'anvil_rate_time_unit = 60s'
sudo postconf -e 'smtpd_client_connection_rate_limit = 20'
sudo postfix reload

anvil_rate_time_unit and smtpd_client_connection_rate_limit work together to cap 20 connections per minute per client — plenty for a normal mail server, far too fast for spammers.

Conclusion

Episode 15 is done. Key takeaways:

  • ClamAV scans attachments; freshclam updates signatures regularly.
  • Amavis orchestrates ClamAV and SpamAssassin in a single filter flow.
  • content_filter routes all email through Amavis; ports 10024/10025 are localhost-only.
  • message_size_limit and $max_message_size prevent giant messages.
  • anvil limits the connection rate per client.

Every email now passes through the virus and spam gate. In episode 16 we tighten the fortress: Hardening & Open Relay Protection — firewall, fail2ban, and making sure Postfix never becomes an open relay. See you in episode 16!

Learn Mailserver - Antivirus & Content Filtering (ClamAV + Amavis) | Learn Mailserver