QMVC (Qmail Mail and Virus Control) 1.7 - HowTo


qmvc Parameter

The CAR Mechanism

Erroneous Emails


AV Scanners

Aux Programs

Special Applications

Performance Issues


QMVC can be used as interface to a Mail Delivery Agent (MDA). In Qmail terms it is used in a "dot-qmail" file which is read by qmail-local. In this respect, QMVC can be compared with Procmail. The scope of QMVC is to provide a system/(virtual-)domain/user-wide control of incoming messages. Thus, QMVC supports Qmail's virtualdomain and qmail-users mechanism.

QMVC (the script qmvc) provides the following functional groups:

QMVC complies to the "CAR(O)" mechanism:

It's up to the user/administrator to define the "CAR triple" to be constructed out of the range of provided Conditions/Actions/Reactions. This is facilitated by means of the control file filters. In any case, QMVC writes a short-hand (qmvc.log) and - in case a Condition is met - a verbose (qmvc.rep) log information. This log information can be analyzed, processed. and displayed in HTML format (qmvc.log => qmcvlog2html, qmvc.rep => virulator). The logs can be monthly summarizied (qmvcmonth), backuped; and displayed yearly (webcalendar) and perhaps per virtualdomain (qmvcportal).

qmvc Parameter

The script qmvc is used in a dot-qmail file prior of delivery to a mailbox/maildir or other instructions (man qmvc). Upon call, qmvc obeys the following parameters (getopts style):

The CAR Mechanism


In QMVC terms, three types of Conditions are taken care of:

  1. The message is erroneous ("errormail"). By means of of the control file mailheaders the presence of mandatory and optional message Headers can be enforced as well as the integrity of the header and the MIME attachments. In addition, QMVC provides an easy interface for e.g. Spam-tagged messages.
  2. The message contains bad data ("badmail"). In particular the message can be checked for (1) badsubjects and (2) badbodytexts. Attachments are analyzed by means of their (3) filename/filetype (badfilenames), their (4) MIME identification (as per magic - badmimetypes), and their (5) loader instructions (badloadertypes). Multiple criteria are allowed in the corresponding control files.
  3. The message contains a virus infected attachment as identified by means of an external AV scanners ("virusmails"). Though QMVC supports currently ClamAV, FSecure, InoculateIT, McAfee, Sophos, and Trend Miro, it's plug-in interface allows to seamlessly integrate virtually any AV scanner available for the UNIX system. The AV scanners are identified to QMVC through the control file scanners. Up to four AV scanners can be used concurrently; the execution order corresponds to the order in the control file scanners.

Note: qmvc performs the checks in the order as detailed above.


QMVC allows five types of Actions:

  1. The message shall be blocked and purged (default). Upon the particular Condition, qmvc issues Return Code 99 to qmail-local which means to stop all further execution of the dot-qmail file. An entry to the logfile qmvc.rep is written.
  2. The message shall be blocked but kept. As with blocked, a Return Code 99 is issued, however qmvc's results (and the message itself) is stored in a save directory for further analysis (see below inspected).
  3. The message shall be trashed (and blocked of course), In this case, only an entry in the logfile qmvc.log is made.
  4. The message shall be bounced. QMVC returns with code 100, telling qmail-send to formulate a generic (QMBF) bounce message and send it to the SMTP sender.
  5. The message shall be inspected. In this case, QMVC keeps the results of it's analysis in a directory for later analysis named after the sender and with unique suffix id.

Otherwise, the message is let through, thus qmvc issues Return Code 0.


While Conditions and Actions are "atomic" instructions, QMVC allows a set of Reactions to be taken in case of a Condition and for an Action which equals block or keep. QMVC can perform three types of Reactions upon the Action "block" and "keep".

Note: qmvc recoginzes qmail-local's environment variable (ie. LOCAL, EXT) which can be used to construct dynamical address by means of the VERP mechanism.


The following Options are available.

Overview of possible Action/Reaction settings

The following table shows the breakdown of honored Action/Reaction combinations. "x" denotes a Reaction is support for a particular Action, and "-" not supported.

 Action\Reaction  Notify Recipient Notify Sender  Inform Guard Forward to Guard












 Inspect | Log









Erroneous Emails

QMVC allows to control erroneous Emails. The following stati can be checked (man qmvc-control):

header=s(trict) - enforce strict RFC 2822 header [1]
date=r(equired) - 'Date:' header field is required [2]
to=r(equired) - 'To:' header field is required [4]
msgid=r(equired) - 'Message-ID:' header field is required [8]
from=r(equired) - 'Form:'/'Sender:' header field is required [16]
subject=r(equired) - 'Subject:' header field is required [32]
mime=s(trict) - enforce strict MIME structure [64]
+field=content - require 'Field' with 'content' [128] (eg. +x-spam-status=yes,)

qmvc does not only check whether a particular field is present, but in addition, if the field is non-empty. The numbers in brackets denote the associated (commulative) error code visible in QMVC's logs.

The last status can be used in conjunction the the Action "block" and Reaction "forward" to simply forward tagged Spam mails to a particular account.


The configuration file filters is the turnkey to define the filter-triple denoting a Condition, a corresponding Action, and Reaction (man qmvc-filters). The fields are separated either by a semi-colon (;) or a vertical bar (|). Sub-Reactions and Options are separated by commas (,).

A typical filters file may look as

# Format: Condition ; Action ; Reaction(s) ; Option (s) ;
# See man qmvc-filters

As can be seen, upon detection of a filter Condition, the subsequent Actions and Reactions can be formulated independently. Irrespectively of their positioning, the Conditions are always worked through in the above mentioned order. However, a Notification send to either Sender or Recipient is always just done once with the first Condition met. Notifications can be multilingual customized.

AV Scanners

While QMVC supports natively the AV Scanners ClamAV, FSecure, Innoculate/IT (CA), McAfee, Sophos, and Trend Micro, it is possible to integrate any "well behaved" AV Scanner under Unix/Linux into QMVC (man qmvc-scanners). This is facilitated via QMVC's AV Scanner Plug-In. You may easily integrate your own AV scanner with an umbrella script named after the executable (called "Engine") av_Engine and perhaps a script check_Engine to verify the current installed virus patterns. The integration of the public domain AV Scanner ClamAV can be used as a good starting point.

The control file scanners is used to actually call up to four concurrently used AV scanners. Here is sample scanners file:

# AV Scanner control file (populated during installation Tue Mar 23 15:14:23 CET 2004)
# Scanner Engine; Scanner Initial; Scanner full Name; Comment
# Seee man page qmvc-scanners
fsav;F;F-Secure's FSAV Version 4.5;
clamscan;C;CLAM's Clamscan;

The file is populated during the installation of QMVC. The first term before the separator (either ";" or "|") denotes the scan engine, the second the initial with is displayed in the qmvc.log and the last is a description for the AV Scanner. This information is displayed in qmvc.rep and used for the virulator.

Pattern Update

While QMVC still supports the download of the virus patterns by means of the script vupdate, I urge everybody to use the AV scanner's own capabilities. The script scanners has been rewritten to care about the currently installed pattern files.

Daemon Mode

Some AV Scanners do not only offer a command line interface for their scanning engine, but rather may work in Client/Server mode. The command line interface in this case is rather slim and works against a Daemon, which does most of the job. In a busy environment, running the AV scanners in Daemon mode is resource-efficient. Daemon mode is supported for ClamAV and FSecure version 4.

Aux Programs

Apart from the main program qmvc, QMVC comes with a set of analysis routines to display QMVC's activity in HTML. While in earlier days upon receipt of an infected mail or a "badmail", a notification message was send to the Recipient (and perhaps the Sender as well), under todays conditions of Virus and Spam (lexical) attacks and faked Sender addresses, this is becomes mostly obsolete. However, QMVC provides excellent tools to display the current "virusmail" and "badmail" situation in HTML files, possibly made available via a HTTP server.


This program is used to simply transform the log file qmvc.log into HTML format (man qmvclog2html). It allows various call options, as discussed in man qmvclog2html. In addition, it provides statistics on the delivery delay due to qmvc.


The virulator performs an analysis of the log file qmvc.rep (man virulator). A detailed analysis of the source'n'sinks of "virusmails" and "badmails" is provided. Calling virulator with the option "-s" includes an analysis of the current AV scanners and their pattern files.


Calling qmvclog2html and virulator with the option "-m" on a daily base builds up a database to display a monthly day-by-day database of all processed mails, the "badmails" and the "virusmails". Using a visual rendering Web client (Mozilla, Opera, IE) moving the cursor over "Die Maus" will give you the number of processed messages for each column. The days in the "Received Emails" diagram are linked with the corresponding qmvc.log file processed by qmvclog2html, the "Filtered Badmails" and "Filtered Virusmails" are linked with virulator's results. In addition, for each involved AV scanner the current hitlist of virii is displayed. The option "-a" allows to automically back up and archive the logfiles qmvc.log, qmvc.rep, and qmvc.error.


Running webcalendar once a year (in all relevant directories ./qmvc/html) builds up a skeleton to serve as yearly and easy accessible overview of QMVC. webcalendar uses the program ncal to build up the calendar, which is currently available on BSD systems only.


Hosting several (virtual)domains and generating the QMVC results in HTML individually for each domain might become tedious. However, it might be tidy to use qmvcportal program to be called in your http server's document root directory. It lists the currently available accounts mapped to virtualdomains and displays them in an HTML frame allowing quick access. In order to distinguish the individual results, it might be necessary to use the "-d" option to include a Domain name for qmvclog2html, virulator, qmvcmonth, and webcalendar results.


The cron daemon is very useful to process QMVC's aux programs automatically on a day-by-day base. Here's the cron-tab for my own (virtual)domain "fehcom":

58 23 * * * /usr/local/bin/qmvclog2html -m -c -d fehcom /home/fehcom/qmvc
58 23 * * * /usr/local/bin/virulator -m -s -c -d fehcom /home/fehcom/qmvc
59 23 * * * /usr/local/bin/qmvcmonth -a -d fehcom /home/fehcom/qmvc


In case your MTA is heavily targeted by particular virus senders (identified by their SMTP Sender envelope address), you may chose to analyze qmvc's topvirus_Sender1 (which is written by the virulator) frequently and check for the top virus mail senders having send you N infected email over the last period. Calling blockvirussender (and shortly before virulator) from root's cron, can be used to populate qmail-smtpd's badmailfrom file to stop reception of emails from these sources. Here's a sample, where newley added entries in badmailfrom are mailed in addition to "admin@example.com".

05 * * * * /usr/local/bin/virulator -c
06 * * * * /usr/local/bin/blockvirussender "admin@expamle.com"

Special Applications

The QMVC "profile"

The set of QMVC configuration files in the control directory is called a profile. An extended profile consists of a control directory qmvc/control and an individual template directory qmvc/tpl.

While the default profile is located in the directory /var/qmvc/control, it is possible to setup user-specific (extended) profiles which take precedence over the default ones; used as fall-backs.

MTA dependent setup of QMVC

In this case, the call of qmvc is included in .qmail-default in /var/qmail/alias.


and perhaps on every local account as per ~/.qmail.

The temporary files and the logs are hosted in the QMVC home directory, usually /var/qmvc/tmp/ and /var/qmvc/log/.

User specific setup

QMVC guarantees privacy of your message scanning if you include the call of qmvc with option '-u' in your local .qmail and perhaps .qmail-default file. By means of the flag '-u' (user) qmvc will look for the directories ~/qmvc/control and ~/qmvc/tpl to use a local (extended) profile.

# ~/.qmail file
|/usr/local/bin/qmvc -u

Furthermore processing and logging of qmvc's actions will be placed in the user's home directory.

QMVC and Qmail's Virtual Domains

Under Qmail, virtual domains are included in the control file virtualdomains and mapped to local users. For Emails targeted to that virtual domain, Qmail prepends the original Recipient address with a 'dash' and the account name of the mapped user.

qmvc recognizes the prepended account name using the option "-v-"; where the last '-' (the default PREPEND; see below) is used to tell qmvc to use the environment variable USER. Incident Emails to the (foreseen) Recipient are processed accordingly. You may want to setup QMVC individually for each user (= virtual domain) with his own profile (= control and template directory), temporary space (with quotas) and own log files.

Include the call to qmvc with the '-uv-' flag in the user-specific .qmail files:

# ~/.qmail
|/usr/local/bin/qmvc -uv-

In addition, generate a specific ~/qmvc/control and perhaps ~/qmvc/tpl directory. Otherwise, you can advice qmvc to share a specific "profile" by means of the '-c' flag:

# ~/.qmail
|/usr/local/bin/qmvc -nu -c /home/vpopmail/mydomain/qmvc -v-

QMVC and the qmail-users mechanism

By means of the qmail-users mechanism it is possible to map a local Recipient to an arbitrary Unix user. This might be in particular the case for virtual domains assigned to users. In order to retain the original Recipient address, it is necessary to provide qmvc the prepended account name PREPEND. This is facilitated by means of

# qmail + vpopmail + vdelivermail
|/usr/local/bin/qmvc -v PREPEND
|/usr/local/vpopmail/bin/vdelivermail '' bounce-no-mailbox

QMVC badbodytexts plug-in (command-API)

While evaluating the badbodytexts control file, qmvc may call an external program to scan the incoming message and to present it's results to qmvc (command-API). Proceed as follows:

Include in the control file badbodytexts an external program and the return code to act upon:

# Lines with preceeding # will not be evaluated
#Kill the boss
|bogofilter -t -u:0

In this example, the program bogofilter is called (which is in the default path). qmvc recognizes the external command by means of the leading "|". In our case, bogofilter is accompanied by the arguments "-t -u". qmvc is adviced to consider the message as badbodytext, if the return code of bogofilter is 0; as provided with ":0" - which is the default.

In the control file filters, enable filtering of bodytext and define an Action and Reaction as usual. Typically:

# Filter File; comments start with '#' in first column; case insensitive
# Format: Condition ; Action ; Reaction(s) ; Option (s) ;
# See man qmvc-filter

In case bogofilter exits with return code 0, the email is blocked for the local (default) account and rather forwarded to a particular Spam-Mailbox of the local user, e.g. available through .qmail-spam. The Option goodmail is used to forward only those emails, which are solely identified via the command-API.

qmvc evaluates the command-API in "hierarchal" mode; thus in case a Condition is met, all following commands are skipped.

Plainmail utility

The plainmail utility is invoked via qmvc's command-API.to forward only the text/plain parts of a (MIME) message to particular recipients. In addition, text/HTML parts are translated to text/plain and included also (thanks to Jim Davis for the html-to-ascii Perl script). The plainmail utility can be called as plug-in within the badbodytexts control file in two distinct ways:

# Lines with preceeding # will not be evaluated
#Kill the boss
|bogofilter -t -u:0
|plainmail newrecipient@example.com:0

Upon recognition of a Forward Address plainmail exits 1 and the message is simply forwarded to "newrecipient@example.com". Due to the hierarchal evaluation of the command-API, recognized Spam emails (by means of bogofilter) are not processed by plainmail.

# Lines with preceding # will not be evaluated
#Kill the boss
|bogofilter -t -u:0

Here, plainmail follows the instructions provided in filters. Enabling the Option "goodmail" only those emails are forwarded, which are not subject of any other qmvc Condition.

Note 1: plainmail honors qmail-local's address variables.

Note 2: plainmail will forward text/plain and (translated) text/HTML MIME parts irrespectively whether they carry redundant information as provided by the MUA.

Filtering outgoing messages

In order to filter outgoing messages by QMVC you have to set up two Qmail instances. Let's assume your domain is "yourdomain.com".

  1. Copy the Qmail control files from the old installation to the new one; except:
  2. Remove locals and smtproutes.
  3. Create a new virtualdomains file with just: ":yourdomain"
|/usr/local/bin/qmvc -uv-

Here, it is important that your standard Qmail is at /var/qmail; otherwise modify the script redirect; in particular the path of qmail-inject.

From now on, your MTA acts in a "split horizon". E-Mails from the Internet come through "qmail" while "qmail2" is responsible for outgoing E-Mails, which will be Virus scanned and eventually forwarded through qmail to the Recipient.

Performance Issues

Depending on the number of messages to filter/scan, the hardware involved, and the setup QMVC will significantly increase the system load (CPU, I/O). However, qmvc allows some tweaking to reduce this load on a busy server without severe security risks.

Using noscantypes (qmvc -n)

Employing the "noscantype" parameter makes qmvc "MIME content aware" regarding the attachments of the message. The idea behind is to classify the attachments according to their MIME content into "harmless" (negative/none-parseable) and "potential dangerous" (positive/parseable) attachments. The "harmless" MIME types (such as ASCII Text, HTML) can be included in the control file noscantypes.

This information of this file is read and used, if qmvc is called with the parameter "-n". Only if a "positive/parseable" attachment is identified, the AV scanners are launched. On the other side, the scanning of text strings is only useful for "negative/none-parseable" attachments. By default - without the parameter "-n" set - all attachements are initially recognized as "positive/parseables" and all may be scanned for text strings.


The order in which qmvc analyses/filters a message is fixed (and manifested in the control file filters) while the order in which the AV scanners are used, depend on their position in the scanners control file. In any case, once a decision is taken to block or bounce a message, it is not be necessary to process it any further. This behaviour of qmvc can be achieved using the additional option "quitasap" in the filters control file. In particular this might be the case, if all messages with certain file names and MIME types shall be blocked.

Multiple AV Scanners

Using several AV Scanners it is advisable to use the most resource-efficient AV Scanner in the first place together with the option "quitasap" and not the most effective; thus filtering out most of the infected messages in the first place. In practice, the most resource-efficient AV scanner might be the one running in Daemon mode.