Mail Server Series — Part 7
In the previous articles, we completed Postfix, Dovecot, SpamAssassin, and Piler installation and integration.
In this part, we focus on a key security component of the entire mail pipeline: Amavis.
Amavis is the central content filter that orchestrates:
- ClamAV → virus detection
- SpamAssassin → spam scoring
- DKIM → verification (inbound) and signing (outbound)
- Policy banks → different behaviors for inbound/outbound
- MIME processing → unzip/unpack attachments for scanning
This part explains how Amavis integrates into your Docker-based mail server and how the full message-security pipeline works.
1. The Role of Amavis
Amavis (A Mail Virus Scanner) acts as a Postfix content_filter middleware, responsible for:
| Function | Description |
|---|---|
| Anti-Virus | Scans attachments and message bodies using ClamAV |
| Anti-Spam | Calls SpamAssassin to assign spam scores |
| DKIM Verification | Verifies DKIM signatures for inbound mail |
| DKIM Signing | Signs outbound emails |
| Policy Bank | Different rules for inbound vs outbound |
| MIME Handler | Automatically extracts zip/rar/gz for scanning |
It is the security “bridge” between incoming/outgoing traffic and the MTA (Postfix).
2. Mail Flow Through Amavis
Inbound Flow (Internet → Internal mailbox)
Internet → Postfix (25)
→ smtp-amavis (10024)
→ Amavis: Virus scan / SpamAssassin / DKIM verify
→ Postfix (10025)
→ Dovecot (LMTP delivery)
Outbound Flow (Internal client → Internet)
Client (587) → Postfix submission
→ smtp-amavis (10026)
→ Amavis: SpamAssassin + DKIM signing
→ Postfix (10027)
→ Internet
Inbound and outbound must be separated because:
- Inbound requires DKIM verification
- Outbound requires DKIM signing
- Spam thresholds differ for inbound/outbound
- Outbound should not block legitimate outgoing messages
3. Amavis Docker Container Structure
Directory layout:
/opt/docker/mail/amavis/
├── amavis.conf
├── 50-user.conf
├── policies/
├── dkim/
│ └── domain.key
├── log/
└── amavis.sh
Run the Docker container:
docker run -dit --name amavis \
--restart=always \
--network intranet-net \
-e TZ=Asia/Taipei \
-v $PWD:/etc/amavis \
-v $PWD/log:/var/log/amavis \
nuface/amavis:1.0
4. Integrating ClamAV
Amavis connects to ClamAV using a local socket:
/var/run/clamav/clamd.ctl
Recommended Docker service:
clamd:
image: clamav/clamav:latest
volumes:
- /opt/docker/mail/clamav:/var/lib/clamav
- /opt/docker/mail/clamav/run:/run/clamav
networks:
- intranet-net
Amavis config:
@av_scanners = (
['ClamAV-clamd',
\&ask_daemon, ["CONTSCAN {}","\Zclamdsock","/run/clamav/clamd.ctl"],
qr/\bOK$/m, qr/\bFOUND$/m,
qr/^.*?: (.*) FOUND$/m ],
);
5. Integrating SpamAssassin
Amavis automatically calls SpamAssassin. In 50-user:
$sa_tag_level_deflt = -999;
$sa_kill_level_deflt = 6.0;
$sa_dsn_cutoff_level = 10;
$spamassassin_tag_headers = 1;
This means:
- All messages receive spam headers
- Messages with score ≥ 6 are treated as spam
- Score ≥ 10 may be rejected
6. DKIM Signing and Verification
Generate DKIM Keys
For domain it.demo.tw:
amavisd-new genrsa /opt/docker/mail/amavis/dkim/it.demo.tw.key 2048
DNS TXT record:
default._domainkey.it.demo.tw IN TXT "v=DKIM1; k=rsa; p=xxxx"
Enable DKIM Signing
$enable_dkim_signing = 1;
dkim_key('it.demo.tw', 'default', '/etc/amavis/dkim/it.demo.tw.key');
Outbound Policy Bank (10026)
$policy_bank{'OUTBOUND'} = {
originating => 1,
enable_dkim_signing => 1,
};
7. Postfix ↔ Amavis Port Assignments
Inbound
smtp inet n - n - - smtpd
-o content_filter=smtp-amavis:[amavis]:10024
Inbound return path:
10025 inet n - n - - smtpd
-o content_filter=
Outbound
submission inet n - n - - smtpd
-o content_filter=smtp-amavis:[amavis]:10026
Outbound return path:
10027 inet n - n - - smtpd
-o content_filter=
8. Policy Banks
Amavis supports policy banks to split logic:
$inet_socket_port = [10024, 10026];
Inbound Policy
$policy_bank{'AMAVIS'} = {
enable_dkim_verification => 1,
};
Outbound Policy
$policy_bank{'ORIGINATING'} = {
enable_dkim_signing => 1,
allow_disclaimers => 1,
};
9. Logs and Debugging
Reload Amavis
docker exec -it amavis amavisd reload
Check DKIM logs
grep DKIM /opt/docker/mail/amavis/log/amavis.log
Run SpamAssassin debug
spamassassin -D < testmail.eml
10. Security Testing
EICAR Test Virus
curl -O https://secure.eicar.org/eicar_com.txt
Amavis should return:
FOUND Eicar-Test-Signature
GTUBE Spam Test
Insert in any email:
XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X
SpamAssassin score should be very high.
DKIM Test
Send mail to Gmail and check:
Authentication-Results: dkim=pass
Conclusion: Amavis is the Core of Your Mail Security Pipeline
By completing Part 7, your environment now has:
- Reliable virus detection (ClamAV)
- Accurate spam scoring (SpamAssassin)
- DKIM verification (inbound)
- DKIM signing (outbound)
- Proper inbound/outbound separation
- Policy-based mail processing
This is one of the most critical parts of a secure mail server.