When running Postfix with clamav-milter you often configure the server to reject the email on SMTP time.
It's possible to let the recipient know, that an email contained a virus and was rejected with the following configuration in /etc/clamav/clamav-milter.conf
SupportMultipleRecipients true
VirusAction /usr/local/bin/virus-alert.py
In order to generate the notification email I created a very simple Python script to compose the email and send it via the local sendmail binary.
While it is very basic on one side (e.g. no logging or exception handling), it is able to decode MIME encoded input headers on the other. A lot of VirusAction example scripts out there don't do that, which was the reason to create it.
Maybe it useful for someone else as well.
/usr/local/bin/virus-alert.py
#!/usr/bin/env python3
import sys
from email.header import decode_header, make_header
import socket
from string import Template
import textwrap
from email.mime.text import MIMEText
import subprocess
hostname = socket.gethostname()
alert_subject = '[Virus-Alert]: An infected E-Mail has been rejected'
alert_sender = 'postmaster@{}'.format(hostname)
msg = {}
msg['hostname'] = hostname
msg['virus'] = sys.argv[1]
msg['id'] = sys.argv[2]
msg['sender'] = str(make_header(decode_header(sys.argv[3])))
msg['recipient'] = str(make_header(decode_header(sys.argv[4])))
msg['subject'] = str(make_header(decode_header(sys.argv[5])))
msg['rid'] = sys.argv[6]
msg['date'] = sys.argv[7]
template = Template('''
This message was generated by the Antivirus system running on $hostname.
The following message was rejected. No further action is required.
Signature : $virus
Date : $date
Subject : $subject
Sender : $sender
Recipient : $recipient
ID : $id
''')
mail = MIMEText(textwrap.dedent(template.substitute(**msg)), 'plain', 'utf-8')
mail['From'] = alert_sender
mail['To'] = msg['recipient']
mail['Subject'] = alert_subject
s = subprocess.Popen(['/usr/sbin/sendmail', '-t', '-oi'], stdin=subprocess.PIPE, universal_newlines=True)
s.communicate(mail.as_string())
The setup can be tested with the following shell command. clamav-milter will invoke the script the same way. The recipient of the test email will be root.
/usr/local/bin/virus-alert.py \
"Heuristics.Phishing.Email.SpoofedDomain" \
"123456" \
"evil-sender@example.com" \
"root" \
"VirusAction Test" \
"123456" \
"$(date --rfc-2822)"
Hello, the script is not running. If I do the test, it works fine, if I send a virus test message, the mail is deleted, but the script is not triggered. Any ideas about that?
Got it runnung: /usr/local/psa/admin/sbin/mailmng-outgoing --add-to-whitelist --sysuser=clamav
Which rights and users are needed to the py file? clamav:clamav and chmod +x?
The script needs to be executable by the user which was used to start clamav-milter. If the file is owned by the same user, chmod 0750 should be fine.
I currently have the problem, that the message is send every hour again.
Example:
A mail is blocked on 12:00 pm, for the next 24 hours I get the information mail every hour again, so that for this one event, I get 24 mails.
How can I change this behavior?
@WebCodePoet The script itself doesn't have any retry logic. So either it is invoked several times or your Mailsetup is delivering the email several times. You could check by adding some debug loglines at the very end of the script, which let you know once it was invoked.
import logging
logging.basicConfig(filename='/tmp/clamav-notification.log', format='%(asctime)s %(message)s', level=logging.INFO)
logging.info(f'invoked for {msg["recipient"]}')