Besides the daemon mode (discussed earlier), sendmail can be run in a number of other useful modes. In this section we'll have a look at some of these. Others we'll leave for later.
One way to run sendmail is to provide it with the name of a recipient as the only command-line argument. For example, the following sends a mail message to george:
% /usr/lib/sendmail george
Multiple recipients can also be given. For example, the following sends a mail message to george, truman, and teddy:
% /usr/lib/sendmail george,truman,teddy
The sendmail program accepts two different kinds of command-line arguments. Arguments that do not begin with a - character (such as george) are assumed to be recipients. Arguments that do begin with a - character are taken as switches that determine the behavior of sendmail. The recipients must always follow all the switched arguments. Any switched arguments that follow recipients will be interpreted as recipient addresses, potentially causing bounced mail.
In this chapter we will cover only a few of these switch-style command-line arguments (see Table 1-1). The complete list of command-line switches, along with an explanation of each, is presented in Chapter 15.
Flag |
Description |
---|---|
-b |
Set operating mode |
-v |
Run in verbose mode |
-d |
Run in debugging mode |
The sendmail program can function in a number of different ways depending on which form of -b argument you use. One form, for example, causes sendmail to display the contents of the queue. Another causes sendmail to rebuild the aliases database. A complete list of the -b command-line mode-setting switches is shown in Table 1-2. We will cover only a few in this chapter.
Form |
Description |
---|---|
-ba |
Use ARPAnet (Grey Book) protocols |
-bD |
Run as a daemon, but don't fork |
-bd |
Run as a daemon |
-bH |
Purge persistent host status |
-bh |
Print persistent host status |
-bi |
Rebuild alias database |
-bm |
Be a mail sender |
-bP |
Print number of entries in the queue (V8.12 and above) |
-bp |
Print the queue |
-bs |
Run SMTP on standard input |
-bt |
Test mode: resolve addresses only |
-bv |
Verify: don't collect or deliver |
-bz |
Freeze the configuration file (obsolete) |
The effects of some of the options in Table 1-2 can also be achieved by running sendmail using a different name. Other names and a description of their results are shown in Table 1-3. Each name can be a hard link with or a symbolic link to sendmail.
Name |
Form |
Description |
---|---|---|
hoststat |
-bh |
Print persistent host status |
mailq |
-bp |
Display the queue |
newaliases |
-bi |
Initialize alias database |
purgestat |
-bH |
Purge persistent host status |
smtpd |
-bd |
Run as a daemon |
The sendmail program can run as a daemon in the background, listening for incoming mail from other machines. The sendmail program reads its configuration file only once, when it first starts as a daemon. It then continues to run forever, never reading the configuration file again. As a consequence, it will never see any changes to that configuration file.
Thus, when you change something in the sendmail.cf configuration file, you always need to kill and restart the sendmail daemon. But before you can kill the daemon, you need to know how to correctly restart it. This information is in the /var/run/sendmail.pid file or one of your system rc files.
On a Berkeley Unix-based system, for example, the daemon is usually started like this:
/usr/sbin/sendmail -bd -q1h
The -bd command-line switch specifies daemon mode. The -q switch tells sendmail how often to look in its queue to process pending mail. The -q1h switch says to process the queue at one (1) hour (h) intervals.
The actual command to start the sendmail daemon on your system might be different from what we've shown. If you manage many different brands of systems, you'll need to know how to start the daemon on all of them.
Killing and restarting the sendmail daemon became easier beginning with V8.7. A single command[13] will kill and restart the daemon. In the following command, you might need to replace the path /var/run with one appropriate to your operating system (such as /etc/mail):
[13] Provided that the daemon was originally started with a full pathname.
% kill -HUP `head -1 /var/run/sendmail.pid`
This single command has the same effect as the two commands shown for V8.6 in the following sections.
Before you can start the sendmail daemon, you need to make sure there is not a daemon running already.
Beginning with V8.6, the pid of the currently running daemon is found in the first line of the /etc/mail/sendmail.pid file. The process of killing the daemon looks like this:
% kill -15 `head -1 /etc/mail/sendmail.pid`
After killing the currently running daemon, you can start a new daemon with the following simple command:
% `tail -1 /etc/mail/sendmail.pid`
Under old versions of sendmail you need to use the ps(1) program to find the pid of the daemon. How you run ps is different on BSD Unix and System V Unix. For BSD Unix the command you use and the output it produces resemble the following:
% ps ax | grep sendmail | grep -v grep 99 ? IW 0:07 /usr/lib/sendmail -bd -q1h % kill -15 99
Here, the leftmost number printed by ps (the 99) was used to kill the daemon.
For System V-based systems you use different arguments for the ps command, and its output differs:
% ps -ae | grep sendmail 99 ? 0:01 sendmail % kill -15 99
Under old versions of sendmail you must look in your system rc files for the way to restart sendmail.
If you forget to kill the daemon before starting a new one, you might see a stream of messages similar to the following, one printed every 5 seconds (probably to your console window):
getrequests: cannot bind: Address already in use getrequests: cannot bind: Address already in use getrequests: cannot bind: Address already in use getrequests: cannot bind: Address already in use getrequests: cannot bind: Address already in use getrequests: cannot bind: Address already in use getrequests: cannot bind: Address already in use getrequests: cannot bind: Address already in use getrequests: cannot bind: Address already in use getrequests: cannot bind: Address already in use getrequests: cannot bind: Address already in use opendaemonsocket: server SMTP socket wedged: exiting
This shows that the attempt to run a second daemon failed.[14]
[14] Note that some multicast-capable versions of Unix allow multiple sendmail daemons to run simultaneously. This is a known bug in the SO_REUSEADDR ioctl(2) call for Transmission Control Protocol (TCP) under multicasting. Contact your vendor for a fix.
The sendmail program can also display the contents of its queue directories. It can do this in two ways: by running as a program named mailq or by being run as sendmail with the -bp command-line switch. Whichever way you run it, the contents of the queue are printed. If the queue is empty, sendmail prints the following:
/var/spool/mqueue is empty
If, on the other hand, mail is waiting in the queue, the output is far more verbose, possibly containing lines similar to these:
/var/spool/mqueue (1 requests) --Q-ID------ --Size-- ----Q-Time------ ------------Sender/Recipient------------ d8BJXvF13031* 702 Thu Jan 1 16:51 <you@here.us.edu> Deferred: Host fbi.dc.gov is down <george@fbi.dc.gov>
Here, the output produced with the -bp switch shows that only one mail message is in the queue. If there were more, each entry would look pretty much the same as this. Each message results in at least two lines of output.
The first line shows details about the message and the sender. The d8BJXvF13031 identifies this message in the queue directory /var/spool/mqueue. The * shows that this message is locked and currently being processed. The 702 is the size of the message body in bytes (the size of the df file as mentioned in Section 1.6.3). The date shows when this message was originally queued. The address shown is the name of the sender.
A second line might appear giving a reason for failure (if there was one). A message can be queued intentionally or because it couldn't immediately be delivered.
The third and possibly subsequent lines show the addresses of the recipients.
If there is more than one queue, each queue will print the preceding information, and the last queue's information will be followed by a line that looks like this:
Total Requests: num
Here, beginning with V8.10, the num will be the total number of messages stored in all the queue directories.
The output produced by the -bp switch is covered more fully in Chapter 11.
Because sendmail might have to search through thousands of names in the aliases file, a version of the file is stored in a separate dbm(3) or db(3) database format file. The use of a database significantly improves lookup speed.
Although early versions of sendmail can automatically update the database whenever the aliases file is changed, that is no longer possible with modern versions.[15] Now, you need to rebuild the database yourself, either by running sendmail using the command newaliases or with the -bi command-line switch. Both do the same thing:
[15] Beginning with V8.10 sendmail, it was recognized that auto-rebuilding the aliases file posed a security risk. For versions V8.10 and V8.11 use of this function was discouraged. Beginning with V8.12, this function has been eliminated. (See AutoRebuildAliases for an explanation of the risk.)
% newaliases % /usr/lib/sendmail -bi
There will be a delay while sendmail rebuilds the aliases database; then a summary of what it did is printed:
/etc/mail/aliases: 859 aliases, longest 615 bytes, 28096 bytes total
This line shows that the database was successfully rebuilt. Beginning with V8.6 sendmail, multiple alias files became possible, so each line (and there might be many) begins with the name of an alias file. The information then displayed is the number of aliases processed, the size of the biggest entry to the right of the : in the aliases file, and the total number of bytes entered into the database. Any mistakes in an alias file will also be printed here.
The aliases file and how to manipulate it are covered in Chapter 12.
A handy tool for checking aliases is the -bv command-line switch. It causes sendmail to recursively look up an alias and report the ultimate real name that it found.
To illustrate, consider the following aliases file:
animals: farmanimals,wildanimals bill-eats: redmeat birds: farmbirds,wildbirds bob-eats: seafood,whitemeat farmanimals: pig,cow farmbirds: chicken,turkey fish: cod,tuna redmeat: animals seafood: fish,shellfish shellfish: crab,lobster ted-eats: bob-eats,bill-eats whitemeat: birds wildanimals: deer,boar wildbirds: quail
Although you can figure out what the name ted-eats ultimately expands to, it is far easier to have sendmail do it for you. By using sendmail, you have the added advantage of being assured accuracy, which is especially important in large and complex aliases files.
In addition to expanding aliases, the -bv switch performs another important function. It verifies whether the expanded aliases are, in fact, deliverable. Consider the following one-line aliases file:
root: fred,larry
Assume that the user fred is the system administrator and has an account on the local machine. The user larry, however, has left, and his account has been removed. You can run sendmail with the -bv switch to find out whether both names are valid:
% /usr/lib/sendmail -bv root
This tells sendmail to verify the name root from the aliases file. Because larry (one of root's aliases) doesn't exist, the output produced looks like this:
larry... User unknown fred... deliverable: mailer local, user fred
The -v command-line switch tells sendmail to run in verbose mode. In that mode, sendmail prints a blow-by-blow[16] description of all the steps it takes in delivering a mail message. To watch sendmail run in verbose mode, send mail to yourself as you did in Section 1.5.1, but this time add a -v switch:
[16] Verbose mode is actually far more powerful than we've shown here.
% /usr/lib/sendmail -v you <sendstuff
The output produced shows that sendmail delivers your mail locally:
you... Connecting to local... you... Sent
When sendmail forwards mail to another machine over a TCP/IP network, it communicates with that other machine using the SMTP protocol. To see what SMTP looks like, run sendmail again, but this time, instead of using you as the recipient, give sendmail your address on another machine:
% /usr/lib/sendmail -v you@remote.domain <sendstuff
The output produced by this command line will look similar to the following:
you@remote.domain... Connecting to remote.domain via smtp... 220 remote.Domain ESMTP Sendmail 8.12.7/8.12.7 ready at Thu, 1 Jan 2002 06:36:12 - 0800 >>> EHLO here.us.edu 250-remote.domain Hello here.us.edu [123.45.67.89], pleased to meet you 250-ENHANCEDSTATUSCODES 250-8BITMIME 250-SIZE 250-DSN 250-ETRN 250-DELIVERBY 250 HELP >>> MAIL From:<you@here.us.edu> SIZE=4537 250 2.1.0 <you@here.us.edu> ... Sender ok >>> RCPT To:<you@remote.domain> 250 2.1.5 <you@remote.domain> ... Recipient ok >>> DATA 354 Enter mail, end with "." on a line by itself >>> . 250 2.0.0 d9L29Nj20475 Message accepted for delivery you@remote.domain... Sent (d9L29Nj20475 Message accepted for delivery) Closing connection to remote.domain >>> QUIT 221 remote.domain closing connection
The lines that begin with numbers and the lines that begin with >>> characters constitute a record of the SMTP conversation. We'll discuss those shortly. The other lines are sendmail on your local machine telling you what it is trying to do and what it has successfully done:
you@remote.domain... Connecting to remote.domain via smtp... ... you@remote.domain... Sent (d9L29Nj20475 Message accepted for delivery) Closing connection to remote.domain
The first line shows to whom the mail is addressed and that the machine remote.domain is on the network. The last two lines show that the mail message was successfully sent.
In the SMTP conversation your local machine displays what it is saying to the remote host by preceding each line with >>> characters. The messages (replies) from the remote machine are displayed with leading numbers. We now explain that conversation.
220 remote.Domain ESMTP Sendmail 8.12.7/8.12.7 ready at Thu, 1 Jan 2002 06:36:12 -0800
Once your sendmail has connected to the remote machine, your sendmail waits for the other machine to initiate the conversation. The other machine says it is ready by sending the number 220 and its fully qualified hostname (the only required information). If the other machine is running sendmail, it can also say the program name is sendmail and state the version. It must also state that it is ready and gives its idea of the local date and time.
The ESMTP means that the remote site understands Extended SMTP.
If sendmail waits too long for a connection without receiving this initial message, it prints "Connection timed out" and queues the mail message for later delivery.
Next the local sendmail sends (the >>>) the word EHLO, for Extended Hello, and its own hostname:
>>> EHLO here.us.edu 250-remote.domain Hello here.us.edu [123.45.67.89], pleased to meet you 250-ENHANCEDSTATUSCODES 250-8BITMIME 250-SIZE 250-DSN 250-ETRN 250-DELIVERBY 250 HELP
The E of the EHLO says that the local sendmail speaks ESMTP too. The remote machine replies with 250, then lists the ESMTP services that it supports. All but the last reply line contain a dash following the 250. That dash signals that an additional reply line will follow. The last line, the HELP line, lacks a dash, and so completes the reply.
One problem that could occur is your machine sending a short hostname ("here") in the EHLO message. This would cause an error because the remote machine wouldn't find here in its domain remote.domain. This is one reason why it is important for your sendmail to always use your machine's fully qualified hostname. A fully qualified name is one that begins with the host's name, followed by a dot, then the entire DNS domain.
If all has gone well so far, the local machine sends the name of the sender of the mail message and the size of the message in bytes:
>>> MAIL From:<you@here.us.edu> SIZE=4537 250 2.1.0 <you@here.us.edu> ... Sender ok
Here, that sender address was accepted by the remote machine, and the size was not too large.
Next the local machine sends the name of the recipient:
>>> RCPT To:<you@remote.domain> 250 2.1.5 <you@remote.domain> ... Recipient ok
If the user you were not known on the remote machine, it might reply with an error of "User unknown." Here, the recipient is ok. Note that ok does not necessarily mean that the address is good. It can still be bounced later. The ok means only that the address is acceptable.
After the envelope information has been sent, your sendmail attempts to send the mail message (header and body combined):
>>> DATA 354 Enter mail, end with "." on a line by itself >>> .
DATA tells the remote host to "get ready." The remote machine says to send the message, and the local machine does so. (The message is not printed as it is sent.) A dot on a line by itself is used to mark the end of a mail message. This is a convention of the SMTP protocol. Because mail messages can contain lines that begin with dots as a valid part of the message, sendmail doubles any dots at the beginning of lines before they are sent.[17] For example, consider when the following text is sent through the mail:
[17] This is called the "hidden dot algorithm" or "dot stuffing" and is documented in RFC2821.
My results matched yours at first: 126.71 126.72 ... 126.79 But then the numbers suddenly jumped high, looking like noise saturated the line.
To prevent any of these lines from being wrongly interpreted as the end of the mail message, sendmail inserts an extra dot at the beginning of any line that begins with a dot, so the actual text transferred is:
My results matched yours at first: 126.71 126.72 .... note extra dot 126.79 But then the numbers suddenly jumped high, looking like noise saturated the line.
The SMTP-server program running at the receiving end (for example, another sendmail) strips those extra dots when it receives the message.
The remote sendmail shows the queue identification number that it assigned to the mail it accepted:
250 2.0.0 d9L29Nj20475 Message accepted for delivery . . . >>> QUIT 221 remote.domain closing connection
The local sendmail sends QUIT to say it is all done. The remote machine acknowledges by closing the connection.
Note that the -v (verbose) switch for sendmail is most useful with mail sent to remote machines. It allows you to watch SMTP conversations as they occur and can help in tracking down why a mail message fails to reach its destination.
The sendmail program can also produce debugging output. The sendmail program is placed in debugging mode by using the -d command-line switch. That switch produces far more information than -v does. To see for yourself, enter the following command line, but substitute your own login name in place of the you :
% /usr/lib/sendmail -d you < /dev/null
This command line produces a great deal of output. We won't explain this output because it is explained in Chapter 16. For now just remember that the sendmail program's debugging output can produce a great deal of information.
In addition to producing lots of debugging information, the -d switch can be modified to display specific debugging information. By adding a numeric argument to the -d switch, output can be limited to one specific aspect of the sendmail program's behavior.
Type in this command line, but change you to your own login name:
% /usr/lib/sendmail -d0 you < /dev/null
Here, the -d0 is the debugging switch with a category of 0. That category limits sendmail's program output to information about how sendmail was compiled. A detailed explanation of that output is covered in -d0.4.
In addition to a category, a level can also be specified. The level adjusts the amount of output produced. A low level produces little output; a high level produces greater and more complex output. The string following the -d has the form:
category.level
For example, enter the following command line:
% /usr/lib/sendmail -d0.1 -bp
The -d0 instructs sendmail to produce general debugging information. The level .1 limits sendmail to its minimal output. That level could have been omitted because a level .1 is the default. Recall that -bp causes sendmail to print the contents of its queue. The output produced looks something like the following:
Version 8.12.7 Compiled with: LOG NAMED_BIND NDBM NETINET NETUNIX NIS SCANF XDEBUG == == == == == == SYSTEM IDENTITY (after readcf) == == == == == == (short domain name) $w = here (canonical domain name) $j = here.us.edu (subdomain name) $m = us.edu (node name) $k = here == == == == == == == == == == == == == == == == == == == == /var/spool/mqueue is empty
Here, the -d0.1 switch causes sendmail to print its version, some information about how it was compiled, and how it interpreted your host (domain) name. Now run the same command line again, but change the level from .1 to .11:
% /usr/lib/sendmail -d0.11 -bp
The increase in the level causes sendmail to print more information:
Version 8.12.7 Compiled with: LOG NAMED_BIND NDBM NETINET NETUNIX NIS SCANF XDEBUG OS Defines: HASFLOCK HASGETUSERSHELL HASINITGROUPS HASLSTAT HASSETREUID HASSETSID HASSETVBUF HASUNAME IDENTPROTO IP_SRCROUTE Config file: /etc/mail/sendmail.cf Pid file: /etc/mail/sendmail.pid canonical name: here.us.edu UUCP nodename: here a.k.a.: [123.45.67.89] == == == == == == SYSTEM IDENTITY (after readcf) == == == == == == (short domain name) $w = here (canonical domain name) $j = here.us.edu (subdomain name) $m = us.edu (node name) $k = here == == == == == == == == == == == == == == == == == == == == /var/spool/mqueue is empty