The SMTP daemon only needs one configuration file to run: /var/qmail/rcpthosts. For simple applications, rcpthosts can contain the same list of domains as locals. It is very important that you set up rcpthosts before starting your SMTP daemon. If you don't, your mail system will be an "open relay," which will transmit mail from anywhere to anywhere and be abused by spammers and blacklisted.
A little later we'll also be setting up a control file to tell the daemon what IP addresses are assigned to local users allowed to relay mail.
Setting up SMTP involves three layers of daemons. Supervise runs tcpserver, which waits for incoming network connections. Each time a remote system connects, tcpserver starts a copy of qmail-smtpd, which collects the incoming message and passes it to qmail-queue for delivery. To run it under supervise, create a pair of directories, and call them /var/qmail/supervise/qmail-smtpd and /var/qmail/supervise/qmail-smtpd/log:
# mkdir /var/qmail/supervise/qmail-smtpd # mkdir /var/qmail/supervise/qmail-smtpd/log # chown root /var/qmail/supervise/qmail-smtpd /var/qmail/supervise/qmail-smtpd/log # mkdir /var/qmail/supervise/qmail-smtpd/log/main # chown qmaill /var/qmail/supervise/qmail-smtpd/log/main
The run script eventually becomes rather complex as you add code to handle local versus remote users, spam filters, and the like, but this is adequate to start (see Example 4-3).
Example 4-3. Running the SMTP daemon
1. #!/bin/sh 2. limit datasize 3m 3. exec tcpserver \ 4. -u
000-v -p -R \ 5. 0 26 \ 6. /var/qmail/bin/qmail-smtpd 2>&1
command on line 2 defends against a
denial-of-service attack in which the attacker feeds the SMTP daemon
a gargantuan message that fills up all of memory and crashes the
machine. Then the
tcpserver command on line 3
accepts SMTP connections and runs qmail-smtpd
for each one. The
flags on line 4 set the user and group numbers; substitute the values
on your system for
-v flag does verbose logging (recommended,
it's not that verbose) and
does "paranoid" validation of
deduced hostnames of remote systems. The
means to not try to collect ident information
from the remote host. (Ident information is rarely useful and a
failed ident request can stall the daemon startup for 25 seconds.) On
line 5, host number
0 means to accept connections
on any IP address assigned to this machine, and
means to use port 26 rather than standard SMTP port 25, which allows
you to run the daemon for testing without interfering with an
existing MTA on port 25. (If there's no other MTA
running, you might as well use port 25.) Finally, line 6 has the
command for tcpserver to run once a connection
is open. At the end,
2>&1 combines any
output to standard error with the regular output so both appear in
the log files.
1. #!/bin/sh 2. exec setuidgid qmaill \ 3. multilog t s4000000 ./main
Once you have all the files created, symlink the smtpservice directory so svscan starts it up:
# chown +x /var/qmail/supervise/qmail-smtpd/run # chown +x /var/qmail/supervise/qmail-smtpd/log/run # ln -s /var/qmail/supervise/qmail-smtpd /service
If you look at log/current, you should see this:
tcpserver: status: 0/40
Now try sending yourself some mail, using Telnet to talk to the SMTP server:
telnet localhost 26Trying 127.0.0.1... Connected to localhost.example.com. Escape character is '^]'. 220 example.com ESMTP
helo localhost250 tom.example.com
mail from:<email@example.com>250 ok
rcpt to:<firstname.lastname@example.org>250 ok
data354 go ahead
Subject: a messagehi . 250 ok 993620568 qp 5602
quit221 example.com Connection closed by foreign host.
The log file for the SMTP daemon in /service/qmail-smtpd/log/main/current should show the connection to the daemon:
tcpserver: status: 1/40 tcpserver: pid 5582 from 127.0.0.1 tcpserver: ok 5582 localhost:127.0.0.1:26 localhost:127.0.0.1::54044 tcpserver: end 5582 status 0 tcpserver: status: 0/40
Check the qmail log in /service/qmail-send/log/main/current to be sure the message has been delivered:
new msg 175297 info msg 175297: bytes 198 from <email@example.com> qp 5845 uid 120 starting delivery 1: msg 175297 to local firstname.lastname@example.org status: local 1/10 remote 0/20 delivery 1: success: did_0+0+1/ status: local 0/10 remote 0/20 end msg 175297
(The numbers vary somewhat; qmail uses the inode number of the spool file as the msg number.)
If this works, you now have a working mail system. If not, the qmail and tcpserver logs should give you hints about what's wrong. The most likely problems are missing directories or configuration files, or incorrect file modes. Also be sure you just didn't make a typing error while telnetting to the SMTP port.
If you want to stop the SMTP daemon, use
just as you did to stop qmail. It's perfectly OK for
the SMTP daemon to be running while qmail isn't. In
this case, incoming mail is queued but won't be
delivered until qmail is started.
Once you believe that qmail works, kill any other mail daemon
listening on port 25, change port 26 to 25 in the
run file, and restart the daemon with
svc -t to start receiving mail on the standard port. The
rest of the examples in this chapter use port 25 rather than port 26,
on the assumption that qmail is now your production mail system, but
for testing, they all work equally well on port 26.
Every mail system on the Internet should define a few standard addresses, such as postmaster, webmaster, and mailer-daemon. (The last is the return address in the From: line of bounce messages.) To define an address, just create a .qmail file for the address in the home directory of the alias user:
# echo fred > /var/qmail/alias/.qmail-postmaster # echo fred > /var/qmail/alias/.qmail-mailer-daemon
(If your login name isn't fred, adjust these examples appropriately.)
Now try using qmail to send mail to postmaster and check that it lands in your mailbox. On a busy system, postmaster gets a lot of mail and you'll probably want to use procmail (discussed later) to sort it to some place other than your personal mailbox.
Your qmail system most likely is a mail hub for a bunch of PCs or workstations. You want to accept mail destined for any address from your users so they can use your mail hub as a "smart host," but for security reasons, you want to accept only mail destined for your own network from elsewhere. Setting up relay control involves two steps: defining the list of locally handled domains for which you'll accept mail from outside and defining the addresses of hosts that are allowed to relay. A third step is to treat mail from local PCs as "injected" mail that must have its headers validated and completed. (As opposed to mail that's relayed from other systems that should already have valid headers, but I save that for later in this chapter.)
You should have already put the list of locally handled domains into /var/qmail/rcpthosts. (If not, do so now.)
Arranging for your users to relay is a little more complicated, because tcpserver and qmail-smtpd provide a general scheme that permits mail to be treated differently depending on what IP address it is received from. You create a file of IP address ranges and environment variables to set and compile it into a CDB database that tcpserver reads. When it receives a connection from an IP address in the database, it passes the corresponding environment variable to qmail-smtpd. For relay control, the relevant variable is RELAYCLIENT. If it's set, qmail-smtpd permits mail to any address, not just the ones in relayhosts, and appends the contents of RELAYCLIENT to each envelope recipient address.
Different people have different preferences for the location of the
TCP rules file. I prefer to keep them with the rest of the qmail
files in a directory called /var/qmail/rules, so
create a file called
/var/qmail/rules/smtprules.txt with contents
like this (the
# lines are comments):
# allow relay from this host 127.:allow,RELAYCLIENT="" # allow relay from other hosts on this network 172.16.42.:allow,RELAYCLIENT="" 172.16.15.1-127.:allow,RELAYCLIENT="" # otherwise, allow connections but no relay :allow
The first line says to accept connections from any address starting with 127, that is, the loopback pseudo-network used for connections from the qmail host to itself, and to create an empty RELAYCLIENT variable. This permits any SMTP connection from the host that qmail is running on to relay. The second and third lines permit relay from any address in 172.16.42.x, and in the range 172.16.15.1 through 172.16.15.127. Replace these lines with ones listing the IP range(s) of your own network. You can have as many lines as you want; more lines don't make the lookup any slower once the file is compiled into a CDB. The last line is the default, and permits connections from anywhere else, but without setting any variables.
Now you must compile the rules into a CDB file, using tcprules. Although it's not hard to run tcprules by hand, it's a pain to do it every time you update your smtprules file (which you will, to block IP addresses that send a lot of spam). It's easy to automate the process using a Makefile to rebuild the CDB, as in Example 4-4.
Example 4-4. Makefile to rebuild the rules file for the SMTP listener
default: smtprules.cdb smtprules.cdb: smtprules.txt cat $> | /usr/local/bin/tcprules $@ $@.$$$$
(The odd looking
$@.$$$$ is the temporary name of
the new CDB, the real name with the PID of the make process added to
ensure uniqueness.) Finally, tell tcpserver to
look at the rules file. Edit
/var/qmail/supervise/qmail-smtpd/run and add an
--x flag to the tcpserver
line, as in Example 4-5.
Example 4-5. Running the SMTP listener
1. #!/bin/sh 2. limit datasize 2m 3. exec \ 4. tcpserver -u
000-v -p -R \ 5. -x/var/qmail/rules/smtprules.cdb 0 25 \ 6. /var/qmail/bin/qmail-smtpd 2>&1
You're all set. Finally, use
/service/supervise/qmail-smtpd to restart
tcpserver with the new arguments.
To test this, send mail from a computer on the local network to an address somewhere else (such as a Hotmail account), and check the logs to verify that it's accepted and mailed back out.