http:// / scripts / service-qmail-smtpd-run.shtml


Most of the changes made by the combined patch involve changes to how qmail-smtpd operates. There are many new options available to a qmail-smtpd service, and if you wish to use those options, you have to set up certain environment variables and structure the final command line in a certain way.

The service-qmail-smtpd-run script is meant to be used as the "run" script for a qmail-smtpd service. The idea is to set the values of the variables in the top part of the script, and the code in the bottom of the script exports the necessary variables, and also uses them to build and run the appropriate final command line.

The script itself has become huge over time, for a few reasons: (1) I was including a "change log" as comments at the top of the script, (2) I was including documentation for every variable in the script, and (3) there were just so many variables being set. I am cleaning up the script so it's not so big. The change log has been moved to a separate file, and this web page now serves as the documentation for the various options, so the script itself is much smaller, and hopefully easier to configure.

Other pages you should read

Credit where credit is due

This script started from Dave Sill's "run" script from Life with qmail, and grew from there. Dave, if you ever read this message, let me offer you my undying thanks for everything you've done for qmail over the years.


File: service-qmail-smtpd-run
Size: 11,028 bytes
Date: 2011-06-30 21:33:34 +0000
MD5: 8945e828951493759e231ee425b4dc3d
SHA-1: 7deff6282fd5f6bda90b9e4f6aafb4147ad49282
RIPEMD-160: 2c179e7f9d74f24931f79c710461b85dfc7b2226
PGP Signature: service-qmail-smtpd-run.asc

Basic options

exec 2>&1

Programs running under *nix systems have two separate output channels. stdout is a program's normal output, which can be sent to a file or to the stdin (input) channel of another program using the shell's ">", ">>", and "|" operators. stderr is a second output channel which is normally used for error messages, so that if somebody runs a program with the output sent to a file, they will still see the error messages on their screen instead of having them go into the file.

The command you see here tells the shell that the script itself, as well as any child processes it may start, should have the stderr channel (which is number 2) redirected into the stdout channel (which is number 1.) We need to do this because, for services running under daemontools, anything that the main service process sends to its stdout channel goes into the log file, and we want any error messages to go into the log.


Most qmail systems have a single instance of qmail, installed in the /var/qmail directory. However, some people install qmail with a different "qmail directory" for some reason, or may be running multiple instances of qmail on the same machine (it's a pain, but it can be done.) This allows you to set the "qmail directory" to which this service should be attached. It's done early in the script because its value is used in several other places below.


This explicitly sets the value of the PATH variable. Every shell script should do this at the beginning, before any commands are actually run- this prevents the system from running the "wrong" binaries. Imagine if you had "$HOME/bin as the first thing in your PATH, and you happened to have a script called "qmail-smtpd" in that directory- if you didn't explicitly set your PATH at the top of the script, and you ran this script by hand to test it, you would accidentally run your "qmail-smtpd" script instead of the real "qmail-smtpd" program. (Yes, it's a rather contrived example- but I have seen this happen before.)


This sets the userid as which the service will run. This is normally "qmaild", although some brain-dead install guides like "qmailrocks" will tell you to use "vpopmail" instead, because the authors of those guides didn't understand how to properly set up an SMTP service to begin with, and blindly copied some other brain-dead install guide they found floating around on the net.

The various program which make up a qmail system are designed to run as different userids, in order to limit the damage which may be done by a currently unknown bug. Running everything as the vpopmail user would allow a bug in something like qmail-scanner to wipe out the contents of your mailboxes- probably not a good thing.

LOCAL=`head -1 $VQ/control/me`

This specifies the "local host name" for several other parts of the script. It does this by reading the /var/qmail/control/me file, which should be correct for most systems.

Options for tcpserver/sslserver


This is the IP address on which the service will listen. THIS MUST BE SET. There are three options for this:

The last option tends to confuse a lot of people- if you have one service listening on "IP=0 PORT=25", you cannot have any other service listening with "PORT=25" at all, regardless of IP address. I've found it's better to just run each qmail-smtpd service on a single IP address, just to avoid the confusion.


Specifies the TCP port number on which the service will listen. The default is 25, which is the standard SMTP port number. If you are setting up an SSL service, you probably want to change this to 465. If you are setting up a TLS service, you probably want 587 here.

Note the warning above, about using "IP=0". If you are doing this in one service, that must be the only service on the machine which uses that port number.


If you set this value to "1", the script will build the final command line to use "sslserver" instead of "tcpserver", and the service will require successful SSL negotiations to take place before qmail-smtpd is ever executed.

A service using this option will normally have "PORT=465", although this is not a hard and fast requirement.


This specifies a file which should contain an SSL key and certificate. For services which use SSL=1, this file is used by sslserver. For services which use STARTTLS, this file is used by qmail-smtpd.

The file itself should be readable, but not writeable, by the userid as which the service runs. For a normal system which runs the service as the "qmaild" user, this means the file should be owned by root, group ownership set to "nofiles" (the group that the qmaild user belongs to), and have permissions "0640" (i.e. owner has read-write, group has read, others have nothing.) THIS FILE SHOULD NOT BE WORLD-READABLE, as it contains the secret key used for setting up the SSL sessions- if an attacker gets a copy of this file, they can de-crypt the encrypted packets and read your users' passwords and email.


This specifies the location of the access control file which tells tcpserver or sslserver what IP addresses it should or should not allow connections from, and what variables should be added to the environment when clients from certain IP addresses connect to the service.

This setting is ignored for "IP=" services. Because these services are listening on a localhost interface, they can only be reached by other processes on the same machine, so there's not really any point in checking the client's IP address (because it will always be


This specifies the maximum number of incoming connections which will be handled at once. The default value, 30, is a good starting point. If your server has the bandwidth, memory, disk, and CPU resources to handle the added load, this number can be raised- however on many systems there is a "hard limit" which you cannot exceed. My experience has been that if you need to raise this past 100, it's time to build a second server and set up one or more mailhubs to share the load.

#DIEMSG="421 $LOCAL Service temporarily unavailable"

#DIEMSG_MAXLOAD="421 $LOCAL Server busy, try again later."
#DIEMSG_MAXCONNIP="421 $LOCAL Too many connections from your IP."
#DIEMSG_MAXCONNC="421 $LOCAL Too many connections from your network."

These options require the "tcpserver limits" patch for ucspi-tcp, available from the ucspi-tcp page on this site. They are used to prevent connections from being accepted if the machine's load average is too high, or to prevent the same IP address or class-C block from connecting too many times at once.

You should consult the documentation on the patch's web site for full details, but the example above sets the following conditions:

Options for programs before qmail-smtpd


These options configure the rblsmtpd program, which checks the client's IP address against one or more RBLs (Realtime Black/Block Lists.)

For those who may be curious, the RBLs listed here are the RBLs that I use on my own server.


This specifies the pathname (or just the name, if it's located in your PATH) of a "greylisting" program. A greylisting program keeps a list of the IP addresses which have connected in the past. Any connections from previously unknown IP addresses will be refused, but if they try again after a certain length of time (usually a few minutes) they will be accepted.

This is a reasonably effective anti-spam tool. Many spam-sending programs will not try again after being rejected once, although some of the spammers are getting smarter and trying again after five minutes.


I have written a greylisting program called jgreylist. There are two versions- the original is written in Perl, and is configured using variables within the script iself, while the newer version is written in C and is configured using the environment variables listed above. I am planning on changing the Perl version to use the same environment variables as the C version, but it hasn't happened yet.

The jgreylist web page documents the meaning of each variable. If you're using this program to implement greylisting, these are the variables you will need to configure it.


This specifies the pathname of the "recordio" program, or if it's in your PATH, it can just be the name. This program sends a copy of the SMTP conversation to the log, which can be rather useful for debugging problems.

Do not use this with STARTTLS services. It causes the connection to die within the first two packets of encrypted data. I don't know exactly what the problem is, but I suspect it has to do with zero bytes in the encrypted data stream.

Options for qmail-smtpd


This specifies the pathname of the "qmail-smtpd" program, or if it's in your PATH, it can just be the name. You probably shouldn't change this.


If you un-comment this variable, its value will override the /var/qmail/control/smtpgreeting file and be used as the initial greeting that qmail-smtpd presents to incoming clients.


If you un-comment this variable, qmail-smtpd will pause for the specified number of seconds before sending its initial greeting. This can be useful as an anti-spammer measure- some spam-sending programs will hang up if they don't see the initial banner within a certain amount of time, however some legitimate email programs also give up after a certain amount of time as well.

I have seen people use values as low as 5 seconds and have good results, I have also seen people who claim this is more effective when set to 60 seconds. Personally, I have found 30 seconds to be a fairly reasonable value in terms of making some spammers give up, while not inconveniencing any legitimate mail servers.


If you un-comment this variable, qmail-stmpd will pause for the delay specified by the GREETDELAY variable (or for one second, if GREETDELAY is zero or not set.) If the client sends any commands before qmail-smtpd sends the initial banner (which is a violation of RFC 2821 section 4.3.1), qmail-smtpd will disconnect the client without accepting any commands.

This has proven to be a lot more effective than just GREETDELAY by itself, since spam-sending programs tend to be rather aggressive and try to send commands as soon as they connect, rather than waiting for the server's initial banner.


If you set this variable to 1, the service will not accept incoming mail unless the STARTTLS command has been sent by the client and the connection is encrypted. This should NOT be used for services on port 25 unless the server is acting as a "private" server which does not accept incoming mail from the world for any domain name.

Note that if qmail-smtpd sees the SSL=1 environment variable (i.e. an SSL service on port 465), it will force this value to 0 in memory, ignoring whatever value you may have set here.

Also note that if you try to use both FORCE_TLS and DENY_TLS at the same time, qmail-smtpd will die and the client will see an error message "421 FORCE_TLS and DENY_TLS both found (#4.3.0)".


If you set this variable to 1, the service will not advertise or accept the STARTTLS command, even if it would otherwise be accepted (i.e. if the necessary key file exists and is usable.) This allows you to have some services which DO support STARTTLS and some which don't.

Note that if qmail-smtpd sees the SSL=1 environment variable (i.e. an SSL service on port 465), it will force this value to 1 in memory, ignoring whatever value you may have set here.

Also note that if you try to use both FORCE_TLS and DENY_TLS at the same time, qmail-smtpd will die and the client will see an error message "421 FORCE_TLS and DENY_TLS both found (#4.3.0)".


This variable tells qmail-smtpd to check the domain name of the envelope sender (the "MAIL FROM" argument) to make sure it's a real domain name, by checking DNS to make sure it has an MX record. If it can't find an MX record, it considers the address to be phony and refuses to accept the MAIL command.

Possible values are:


This turns on one of Russell Nelson's early relay rejection patches, which checks each recipient address for multiple "@" characters, or for any "%" or "!" characters to the left of the "@" character, and refuses the RCPT command if it sees them. This is only an issue when you're dealing with certain automated relay testers, which try to trigger bugs in old versions of sendmail which involved these characters- qmail is not, and has never been, affected by them.

Personally, I don't use this feature, and I don't think others should use it. According to RFC 2821 section 4.1.2, the "%" and "!" characters are valid within a mailbox name. Besides, most automated relay testers are broken- the only reliable one I've seen, which truly doesn't report you as an open relay until it actually RECEIVES a message relayed through your server, is the test done by NJABL (see "Requested testing" on the page.)


These variables will cause qmail-smtpd to log all successful "MAIL FROM" and "RCPT TO" commands.


Under qmail, the SMTP "HELP" command simply returns a message with the URL to djb's original qmail web page. This variable adds a second line to the message which identifies what version of my combined patch is running. I originally added this as a debugging feature (because at one point I was working with three different versions, trying to debug a problem, and it helped me keep track of which version was which) and then decided to leave it in there, as something which has to be explicitly turned on.

The script defaults to NOT using this feature. If a bug is found in the future which has security implications, I don't think it makes much sense to give the attackers an easy way to scan for machines running a certain version of the combined patch. However, the option is here if you decide you want to use it all the time.

Options for the AUTH command

The script supports two different methods of validating AUTH commands received from clients.

The "CHECKPW" method uses a checkpassword program, such as vpopmail's vchkpw, to validate the credentials sent by the client. This works and it's fairly portable, however it suffers from a few problems:

The "AUTH_CDB" method uses, surprisingly enough, functionality provided by the AUTH_CDB patch, where all of the the valid userids (or email addresses) and their encrypted passwords are stored in a .cdb file (which normally has the name "auth.cdb".) This method has the following advantages:

To be fair, there is a disadvantage to using the AUTH_CDB method- you need to build the auth.cdb file, you need to rebuild it whenever a mailbox is added or removed, or a password is changed, and if you're running multiple servers, you need to push the new file out to the mailhubs.

I have a qmail-updater service on my machine which builds a new auth.cdb file (and would push it out to other mailhubs, if I were using mailhubs) whenever it's triggered. I also use vpopmail's "onchange" functionality (which I also wrote) to trigger the service whenever something changes. This means that whenever a domain or mailbox is added, removed, or changed, my auth.cdb and validrcptto.cdb files are both automatically updated and active within about five seconds.


If you wish to support the AUTH command at all, you need to change this to say "AUTH=1".


If you wish to require a valid AUTH command before accepting any mail, change this to say "REQUIRE_AUTH=1".

If you do this for a service running on port 25 which accepts incoming mail from the rest of the internet, you will effectively cut your server off from accepting incoming mail, because the millions of other mail servers out there do not have valid AUTH credentials for your server, and they wouldn't use them even if they did. BE CAREFUL.


I have added a specific security check to qmail-smtpd which prevents it from advertising or accepting the AUTH command unless the connection is secure, either because a successful STARTTLS command has been processed, or because the service was secured using sslserver (technically, if the "SSL=1" variable is found, but don't use that to override the security check because it affects other things within qmail-smtpd as well.) This is because the AUTH LOGIN and AUTH PLAIN methods encode the password using BASE-64 rather than encrypting it, which means that anybody who can get a packet sniffer into the right place could read your users' passwords right off the wire.

If you have a valid reason to allow users to send their passwords to the server using what amounts to plain text (i.e. if the server is only accessible from within a secured network) you can set this variable to "1", and the security check will be bypassed.

Please be careful with this option. Don't think of it as a way to keep users from having to turn on an SSL or TLS option in their MUA (Mail User Agent, the email program on their desktop.) Remember, all it takes is for a spammer to find ONE of your users' passwords, and they will be able to use your server as a relay to send out spam- which will get your server listed on a bunch of blacklists and cause most of the internet to not want to accept mail from your IP address.

Options for the AUTH_CDB method


This specifies the name of the .cdb file which qmail-smtpd will use to validate AUTH commands. If this variable exists, qmail-smtpd will use the AUTH_CDB method instead of the CHECKPW method, and the script will build the final command line without the checkpassword program and its arguments.

Options for the CHECKPW method


This specifies the full pathname of the checkpassword program you wish to use. You should specify the full path here- qmail-smtpd will not try to search for it in the PATH, and making the kernel run a copy of /bin/sh just to search the path only slows things down even further.

TRUE=`which true`

This specifies the full pathname of whatever program the checkpassword program should exec after processing a valid AUTH command. Again, you should specify the full pathname of the program, in order to avoid the overhead of searching the PATH.

Environment changes for all AUTH users


The AUTH_SET patch allows for environment variables to be added, changed, or removed after a successful AUTH command is processed. However, not all variables can be changed. The list you see here is all of the variables which can be changed, at least in terms of functionality within qmail-smtpd itself. You can also add, change, or remove environment variables which affect the operation of simscan, qmail-scanner, and any of the programs they execute.

Note that these changes happen for EVERY client who successfully authenticates. This mechanism does not provide a way to make "per-user" changes to environment variables, however the AUTH_CDB method does.

In combined patch version 7.02, the per-user changes made by the AUTH_CDB mechanism happened before changes made by the AUTH_SET mechanism. In version 7.03 I reversed the order, so that per-user changes can override any "all users" changes.

Options for the validrcptto.cdb mechanism

Normally, qmail-smtpd only verifies the domain name portion of the recipients. The validrpctto.cdb patch gives it the ability to check the mailbox names as well. It uses a .cdb file (normally named "validrcptto.cdb") containing every valid email address on the server, and checks all recipients against this file. If it doesn't find a match, it rejects the RCPT command.

If the file contains any entries of the form "mailbox-default@domain", then any "mailbox-whatever" names will also be accepted. In addition, any entries of the form "@domain" tell it to accept any mailbox name within the domain.


This specifies the location of the .cdb file containing the valid email addresses. If this variable is not set, the check will not be done and your server will accept mail for any mailbox within your domains, whether the mailbox actually exists or not.


One of the dangers of doing this type of mailbox check is that spammers can conduct a "dictionary attack" on your server, where they try a whole collection of possible mailbox names to see which ones are accepted and rejected, thereby building a list of the valid email addresses on your server. With this variable, you can set a limit for how many RCPT commands with unknown addresses can be entered before qmail-smtpd will forcibly hang up on the client without accepting ANY mail.

If this variable is not set, the value 10 will be used. If you wish to have no limit at all, you must explicitly set this to 0.


This variable controls how much logging is done by the validrcptto.cdb code within qmail-smtpd. Possible values are:

Options for the SPF mechanism

SPF is a mechanism which allows the owner of a domain to tell the world, using their DNS records, what IP addresses are allowed to send mail which claims to be "From" their domain name. Mail servers can then use that list to verify that incoming messages are coming from IP addresses which are authorized to send such messages.

For example, my own SPF record for "" contains the IP addresses of my server, Blackberry's mail servers (because I sometimes use my Blackberry to send mail), the dyndns name of my cable modem at home, and a flag which basically says "and no others." If your server receives a message claiming to be from my domain, but the IP which hands you the message isn't on this list, you know that the message is forged- and the SPF code can reject the message. has more information about how SPF works, and how to create SPF records for your own domains. is the home page for the actual SPF patch which is part of my combined patch.


This variable controls whether or not the SPF checks are done, and when to reject the messages. Possible values are:

Basically, don't use any value higher than 3.


Setting this variable to a non-zero value will cause qmail-smtpd to log the results of each SPF check it does. The log message will be the same "Received-SPF" header which is added to the message.


Some spammers have found a way to work around SPF filtering. They simply purchase their own bogus domain names for ten dollars each, give them SPF records which contain "+all" (which says that every IP on the planet has permission to send mail "From" their domain), and use their own domain name as the sender address in their spam.

If this variable contains a non-zero value, any such SPF record will be changed from "+all" to "-all" before the SPF test is performed. Since most spammers have "+all" as the only term in their SPF record, this effectively blocks every IP address.

Options for the Domainkeys mechanism

Note that in order to support Domainkeys, you must apply an add-on patch after my combined patch. has details about the add-on patch, as well as full documentation for these variables.


Setting DOMAINKEYS=1 will enable Domainkeys checking and signing for incoming mail.


These variables control how the results of the verifications should be handled, and where to find the keys in order to do signing for messages sent by users who have authenticated. These options are VERY detailed- if you plan to use Domainkeys, you should read for a full explanation of the format of these variables.

Options for programs after qmail-smtpd

Under the original qmail design, when qmail-smtpd is finished receiving the incoming message (i.e. after the "." line at the end of the "DATA" transaction is received) it passes the message to the qmail-queue program, which adds the message to the queue. The QMAILQUEUE variable, if it exists, should contain the pathname of an alternate program which qmail-smtpd will call instead.

This mechanism is commonly used to make qmail-smtpd pass the message to some other program, which may perform any number of tests on the message and then pass it along to the real qmail-queue program. The simscan and qmail-scanner programs both work like this. In theory, other programs could be written to work in the same way, however I'm not aware of any other programs out there.

Many people use qmail-scanner because it existed first, or because the instructions they followed when they set up their server told them to use it (or installed it for them, without their understanding what was going on- yes, I'm talking about "qmailrocks".) I used it myself for several years. It does work, and because it's written in Perl, it's fairly easy to customize if you want or need to do so. However, because it's written in Perl, it runs a lot more slowly than you might want on a busy server.

I switched over to using simscan in August 2007. I like it because it's written in C, which is compiled to machine code, and therefore runs much more quickly than qmail-scanner. It also doesn't suffer from another qmail-scanner problem- if Perl on your system doesn't correctly support "setuid" programs, you have to build a separate wrapper in order to make it run as the correct userid. The only down-side to simscan is that it doesn't support as many different virus scanners as qmail-scanner (it supports ClamAV and Trophie, where qmail-scanner supports a few others) however I don't have any need for the others- I use ClamAV on my servers and have been happy with it.

There are different options available, depending on whether you are using qmail-scanner or simscan.

Options for simscan


In order to use simscan, you should un-comment this line. Obviously, if your simscan executable is stored in some other location, you should change the value of the variable to point to it.


Simscan includes a "feature" which performs a "P0F check" to determine the operating system of the client (the machine which is sending the message to us.) At first glance, not a bad idea. However, what simscan DOES with that information is rather strange: If the client is found to be running Microsoft Windows, it picks a random number from 1 to 100, and if that number is 85 or lower, it rejects the message.

I don't know whose idea this was, but in my not so humble opinion, this is one of the most asinine things I've ever heard of. Those who know me, know that I'm not a big fan of Microsoft- but I do understand that there are companies out there who have no choice but to use a Microsoft product, or some third-party MTA running on Windows, as their mail server. I'm sorry, but refusing messages at random because they were sent from a Windows machine is WRONG.

Luckily, they included a way to disable this "feature". simscan bypasses this check if it sees the NOP0FCHECK variable in the environment.

I have written the script with this line un-commented by default. Please do not comment this line out unless you actually WANT to randomly drop messages from Windows machines.


These options have to do with debugging simscan. Setting SIMSCAN_DEBUG to a value between 1 and 4 will send debugging messages to the log when simscan runs, with higher values resulting in more detailed messages.

I have written several patches for simscan-1.3.1. One of them adds a bit of extra detail regarding a problem I was having with clamdscan, and resulted in my being able to write a patch to enable simscan to recognize both ClamAV database formats (ClamAV changed the format when version 0.90 came out, but sometimes the newer programs will fall back and use the older file format- so simscan needs to be able to handle both formats.)

The patch gives you the ability to NOT delete files from the simscan directory, either when there was a problem running clamdscan, or every time it runs (i.e. keep every message.)

Setting SIMSCAN_DEBUG_FILES=1 tells simscan not to delete the files from the simscan directory if there were problems with clamdscan.

Setting SIMSCAN_DEBUG_FILES=2 tells simscan to never delete the files from the simscan directory. Be careful with this option, it should ONLY be used to debug specific problems and should not be left running all the time, otherwise it will fill up the filesystem over times.

Options for qmail-scanner


In order to use qmail-scanner, you should uncomment ONE of these lines. If your system's Perl doesn't handle setuid scripts correctly and you had to build the C wrapper program, you should un-comment the first line. Otherwise, un-comment the second line.