I've noticed that a lot of people don't seem to understand how qmail handles (or doesn't handle) relaying- deciding when to accept messages, especially if you're "sending mail out" to an email address which is part of a domain which isn't handled on the server itself.
Hopefully this page will clarify how it works.
As you may know, qmail itself is made up of several "smaller" programs, each of which does its one little piece of the overall mail server job, and does it well. The program which handles incoming SMTP is called qmail-smtpd.
By default, qmail-smtpd will accept ANY incoming message.
Let me repeat that.
By default, qmail-smtpd will accept ANY incoming message.
If you're thinking "this sounds like an open relay", you are correct. It IS an open relay. BY DEFAULT, qmail-smtpd is an open relay.
Of course, an open relay is a BAD THING(tm). This is why qmail has
the /var/qmail/control/rcpthosts
and
/var/qmail/control/morercpthosts.cdb
files. IF THESE
FILES EXIST, qmail-smtpd will not accept mail for any domain which is
not listed in them.
This is why almost every "run" script for an SMTP service, including
my own, includes code
which makes sure that the rcpthosts
file exists, and
refuses to start the SMTP service if it does not exist.
When a client connects to qmail-smtpd and wants to send a message to your server, qmail-smtpd walks through a set of tests to determine whether or not to accept the message. The logic behind those tests looks like this:
If the RELAYCLIENT
environment variable is
set, accept the message. The normal method of setting this
variable is by adding a command to the tcpserver access control file
which sets the variable based on the client's IP address. This normally
looks like x.x.x.x:allow,RELAYCLIENT="".
With the appropriate patch, if a successful AUTH command has been sent by the client, accept the message.
If the rcpthosts
file does not exist,
accept the message. This condition should never
happen.
If the domain name portion of the recipient is listed in the
rcpthosts
file (i.e. your server legitimately
handles incoming mail for that domain), accept the
message.
If the domain name portion of the recipient is listed in the
morercpthosts.cdb
file (i.e. your server
legitimately handles incoming mail for that domain), accept the
message.
If none of these conditions are true, qmail-smtpd will refuse to accept the message and the SMTP client will receive an error message which looks like this:
553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)
While this is the most commonly seen message, other messages are possible depending on which anti-SPAM patches you are using. These other messages should be self-explanatory, this web page is not going to spend a lot of time trying to guess and explain every possible message.
The sections below provide more detail about each of the conditions which can make qmail-smtpd accept a message.
qmail-smtpd will accept an incoming message if an environment variable called RELAYCLIENT exists when qmail-smtpd starts. This variable normally does not exist, unless you are purposely setting up an open relay for some reason.
Normally qmail-smtpd runs as a child under a program called tcpserver. tcpserver works by listening to a specific TCP port, usually on a single IP address but by specifying the IP address 0 it will listen to every IP address on the machine.
tcpserver supports an access list mechanism (based on cdb files again) which controls the IP addresses which are and are not allowed to connect to your server. If the connection is allowed, tcpserver runs the actual command to provide your service (in this case, "qmail-smtpd") with the socket set up as stdin/stdout for that command. It also sets some environment variables to tell the command things like what the client's IP address is, since the command would otherwise have no way to tell.
The access control file can also be used to add your own environment variables when a client connects from a certain IP range. For example, if you have a machine or a set of machines which should always be allowed to send mail through your server, you can set their IP address in the access control file so that it creates a RELAYCLIENT environment variable (which qmail-smtpd recognizes as giving the client permission to relay, bypassing the rcpthosts check.)
For example...
127.:allow,RELAYCLIENT=""
192.168.1.:allow,RELAYCLIENT=""
210.:deny
=:allow
:allow,RBLSMTPD="-We do not accept mail from IP addresses without reverse DNS."
What this means:
Clients connecting from a 127.x.x.x IP address (which almost always means the server connecting to itself, unless you're doing something really strange with IP addresses) will have the RELAYCLIENT variable created and set to an empty value before the service program runs.
Clients whose IP address is 192.168.1.x (for example, a local internal network) will also have the RELAYCLIENT variable created before the service program is started.
Clients whose IP address starts with 210 will be denied. If they try to connect, the machine will accept their connection and then immediately close the connection without sending or receiving any data.
Clients whose IP addresses have PTR records (i.e. "reverse DNS") will be allowed to connect. No additional environment variables are set. Note that the mechanics of this check are modified by the "-p" and "-P" flags to tcpserver, see the tcpserver documentation for more information.
Other clients (i.e. those without reverse DNS) will be allowed to connect, and a variable called RBLSMTPD will be created with the value shown before the service program is started.
The choice of which environment variables you want to add will depend on what service program or programs you are running. For example, the RBLSMTPD variable is only useful if the rblsmtpd program is in the command line before qmail-smtpd.
qmail-smtpd will accept an incoming message if the client has sent a successful AUTH command in the current session.
The AUTH command allows a client to "prove" that they are authorized to relay, based on a userid and password (or other credentials, depending on how the server is configured.) Most servers use the same id/password database for the AUTH commands that they use for access to POP3 or IMAP mailboxes.
This page has more information on the AUTH command, including a walk-through of how to test your server to make sure the command is being properly advertised and/or accepted.
qmail-smtpd will accept an incoming message if the domain portion (the portion to the right of the "@" sign) of the recipient's address is listed in either the /var/qmail/control/rcpthosts or /var/qmail/control/morercpthosts.cdb file.
However, if the rcpthosts file does not exist, qmail-smtpd will assume that your intent is to run as an open relay, meaning that you wish to accept mail from anywhere in the world, FOR anybody in the world. Do not do this unless the machine itself is behind a firewall which blocks incoming traffic on TCP port 25, or your server WILL be found and abused by spammers.
Why two files? When qmail-smtpd starts, it has to read the entire contents of the rcpthosts file into memory so that it has the list of domains to check against. For servers with a small list (i.e. less than 50 domain names) this is fine, but for ISP mail servers which handle mail for hundreds or thousands of domain names, the time it takes to read the file and sort it into memory can slow down mail processing.
Because cdb files (which are read-only database files) are blindingly fast, it takes less time to check whether a given domain name exists in a 500-entry morercpthosts.cdb file than it does to read 500 lines of text into memory. Multiply this by the number of messages a busy mail server has to deal with (several messages per second in some cases) and you can see why using a cdb file is a good idea.
Many people have asked whether they should add their own email address, or hostname, or IP address, to these files... the answer is no. These files are only used to check the domain names from the recipient addresses on the messages which are sent to the server. For information on how to "add IP addresses", see the RELAYCLIENT section below.