Red Hat Linux 7 Unleashed

Red Hat Linux 7 Unleashed

By William Ball

SMTP and sendmail

The Simple Mail Transfer Protocol (SMTP) is the established standard for transferring mail over the Internet. The sendmail program provides the services needed to support SMTP connections for Linux.

This section covers the details you need in order to understand, install, and configure the sendmail package. Before getting into the details, however, let's take a moment to discuss the SMTP protocol in better detail and how the Domain Name Service (DNS) interacts with email across the Internet. (See Chapter 14, "Domain Name Service and Dynamic Host Configuration Protocol," for more details on DNS configuration.)

Armed with a better understanding of the protocols, you can take on trying to understand sendmail itself, beginning with the various tasks that sendmail performs, such as mail routing and header rewriting, as well as its corresponding configuration files.

Internet Mail Protocols

To understand the jobs that sendmail performs, you need to know a little about Internet protocols. Protocols are simply agreed-upon standards that software and hardware use to communicate.

Protocols are usually layered, with higher levels using the lower ones as building blocks. For example, the Internet Protocol (IP) sends packets of data back and forth without building an end-to-end connection such as that used by SMTP and other higher-level protocols. The Transmission Control Protocol (TCP), which is built on top of IP, provides for connection-oriented services such as those used by telnet and the Simple Mail Transfer Protocol (SMTP). The TCP/IP protocols provide the basic network services for the Internet. Higher-level protocols such as the File Transfer Protocol (FTP) and SMTP are built on top of TCP/IP. The advantage of such layering is that programs that implement the SMTP or FTP protocols don't have to know anything about transporting packets on the network and making connections to other hosts. They can use the services provided by TCP/IP for that job.

SMTP defines how programs exchange email on the Internet. It doesn't matter whether the program exchanging the email is sendmail running on a Sun workstation or an SMTP client written for an Apple Macintosh. As long as both programs implement the SMTP protocol correctly, they can exchange mail.

The following example of the SMTP protocol in action might help demystify it a little. The user betty at gonzo.gov is sending mail to joe at http://whizzer.com:

$ /usr/sbin/sendmail -v joe@whizzer.com < letter
joe@whizzer.com... Connecting to whizzer.com via tcp...
Trying 123.45.67.1...  connected.
220-whizzer.com SMTP ready at Mon, 6 Jun 1997 18:56:22 -0500
220 ESMTP spoken here
>>> HELLO gonzo.gov
250 whizzer.com Hello gonzo.gov [123.45.67.2], pleased to meet you
>>> MAIL From:<betty@gonzo.gov>
250 <betty@gonzo.gov>... Sender ok
>>> RCPT To:<joe@whizzer.com>
250 <joe@whizzer.com>... Recipient ok
>>> DATA
354 Enter mail, end with "." on a line by itself
>>> .
250 SAA08680 Message accepted for delivery
>>> QUIT
221 whizzer.com closing connection
joe@whizzer.com... Sent
$ 

The first line shows one way to invoke sendmail directly rather than letting your favorite Mail User Agent (MUA), such as Elm, Pine, or Mutt, do it for you. The - v option tells sendmail to be verbose and shows you the SMTP dialog. The other lines show an SMTP client and server carrying on a conversation. Lines prefaced with >>> indicate the client (or sender) on gonzo.gov, and the lines that immediately follow are the replies of the server (or receiver) on http://whizzer.com. The first line beginning with 220 is the SMTP server announcing itself after the initial connection, giving its hostname and the date and time, and the second line informs the client that this server understands the Extended SMTP protocol (ESMTP) in case the client wants to use it. Numbers such as 220 are reply codes that the SMTP client uses to communicate with the SMTP server. The text following the reply codes is only for human consumption.

Although this dialog still might look a little mysterious, it will soon be very familiar if you take the time to read RFCs 821 and 1869. Running sendmail with its -v option also will help you understand how an SMTP dialog works.

The Domain Name System and Email

Names like http://whizzer.com are convenient for humans, but computers insist on using numerical IP addresses like 123.45.67.1. The Domain Name Service (DNS) provides this hostname-to-IP-address translation and other important information.

In the old days, only a few thousand hosts were on the Internet. All hosts were registered with the Network Information Center (NIC), which distributed a host table listing the hostnames and IP addresses of all the hosts on the Internet. Those simple times are gone forever. No one really knows how many hosts are connected to the Internet now, but they number in the millions. It is physically impossible for an administrative entity such as the NIC to keep track of every Internet address. Thus was born the DNS.

The DNS distributes the authority for naming and numbering hosts to autonomous administrative domains. For example, a company called http://whizzer.com can maintain all the information about the hosts in its own domain. When the host http://a.whizzer.com wants to send mail or telnet to the host http://b.whizzer.com, it sends an inquiry over the network to the http://whizzer.com nameserver, which might run on a host named http://ns.whizzer.com. The http://ns.whizzer.com nameserver replies to http://a.whizzer.com with the IP address of http://b.whizzer.com (and possibly other information), and the mail is sent or the telnet connection made. Because http://ns.whizzer.com is authoritative for the http://whizzer.com domain, it can answer any inquiries about whizzer.com hosts regardless of where they originate. The authority for naming hosts in this domain has been delegated.

Now, what if someone on a.whizzer.com wants to send mail to joe@gonzo.gov? http://ns.whizzer.com has no information about hosts in the gonzo.gov domain, but it knows how to find this information. When a nameserver receives a request for a host in a domain for which it has no information, it asks the root nameservers for the names and IP addresses of servers that are authoritative for that domain—in this case, gonzo.gov. The root nameserver gives the http://ns.whizzer.com nameserver the names and IP addresses of hosts running nameservers with authority for gonzo.gov. The http://ns.whizzer.com nameserver inquires of them and forwards the reply to http://a.whizzer.com.

From the preceding description, you can see that the DNS is a large, distributed database containing mappings between hostnames and IP addresses, but it contains other information as well. When a program such as sendmail delivers mail, it must translate the recipient's hostname into an IP address. This bit of DNS data is known as an A (Address) record, and it is the most fundamental data about a host. A second piece of host data is the Mail eXchanger (MX) record. An MX record for a host such as http://a.whizzer.com lists one or more hosts willing to receive mail for it.

What's the point? Why shouldn't http://a.whizzer.com simply receive its own mail and be done with the process? Isn't a postmaster's life complicated enough without having to worry about mail exchangers? Well, although it's true that the postmaster's life is often overly complicated, MX records serve some useful purposes:

Mail Delivery and MX Records

When an SMTP client delivers mail to a host, it must do more than translate the hostname into an IP address. First, the client asks for MX records. If any exist, it sorts them according to the priority given in the record. For example, http://whizzer.com might have MX records listing the hosts http://mailhub.whizzer.com, http://walrus.whizzer.com, and mailer.gonzo.gov as the hosts willing to receive mail for it (and the "host" http://whizzer.com might not exist except as an MX record, meaning that there might be no IP address available for it). Although any of these hosts will accept mail for http://whizzer.com, the MX priorities specify which host the SMTP client should try first, and properly behaved SMTP clients will do so. In this case, the system administrator has set up a primary mail relay http://mailhub.whizzer.com and an onsite backup http://walrus.whizzer.com, and has arranged with the system administrator at mailer.gonzo.gov for an offsite backup. The administrators have set the MX priorities so SMTP clients will try the primary mail relay first, the onsite backup second, and the offsite backup third. This setup takes care of problems with the vendor who doesn't ship your parts on time and the wayward backhoe operator who severs the fiber-optic cable that provides your site's Internet connection.

After collecting and sorting the MX records, the SMTP client gathers the IP addresses for the MX hosts and attempts delivery to them in order of MX preference. You should keep this fact in mind when you're debugging mail problems. Just because a letter is addressed to joe@whizzer.com doesn't necessarily mean a host named http://whizzer.com exists. Even if such a host does exist, it might not be the host that is supposed to receive the mail. You can easily check this using the nslookup command to check if any MX records are being used for a given domain name. For example:

# nslookup -querytype=mx linux.org
Server:  dns1.whizzer.com
Address:  192.168.1.2

Non-authoritative answer:
linux.org       preference = 30, mail exchanger = border-ai.invlogic.com
linux.org       preference = 10, mail exchanger = mail.linux.org
linux.org       preference = 20, mail exchanger = router.invlogic.com

Authoritative answers can be found from:
linux.org       nameserver = NS.invlogic.com
linux.org       nameserver = NS0.AITCOM.NET
border-ai.invlogic.com  internet address = 205.134.175.254
mail.linux.org  internet address = 198.182.196.60
router.invlogic.com     internet address = 198.182.196.1
NS.invlogic.com internet address = 205.134.175.254
NS0.AITCOM.NET  internet address = 208.234.1.34

The non-authoritative answer means that you didn't get the answer from one of the DNS servers authoritative for the domain linux.org. A list of these authoritative servers is the last part of the response. The MX records that you requested are listed with their preference value. A lower preference means that these servers are tried first followed by higher preferences until the mail is delivered successfully. For the full details on configuring DNS for Linux, see Chapter 20, "TCP/IP Network Management."

Header and Envelope Addresses

The distinction between header and envelope addresses is important because mail routers can process them differently. An example will help explain the difference between the two.

Suppose you have a paper memo you want to send to your colleagues Mary and Bill at the Gonzo Corporation and Ted and Ben at the Whizzer company. You give a copy of the memo to your trusty mail clerk Alphonse, who notes the multiple recipients. Because he's a clever fellow who wants to save your company 66 cents, Alphonse makes two copies of the memo and puts each in an envelope addressed to the respective companies instead of sending a copy to each recipient. On the cover of the Gonzo envelope, he writes "Mary and Bill," and on the cover of the Whizzer envelope, he writes "Ted and Ben." When Alphonse's counterparts at Gonzo and Whizzer receive the envelopes, they make copies of the memo and send them to Mary, Bill, Ted, and Ben without inspecting the addresses in the memo itself. As far as the Gonzo and Whizzer mail clerks are concerned, the memo itself might be addressed to the Pope. They care only about the envelope addresses.

SMTP clients and servers work in much the same way. Suppose joe@gonzo.gov sends mail to his colleagues betty@zippy.gov and fred@whizzer.com. The recipient list in the letter's headers might look like this:

To: betty@zippy.gov, fred@whizzer.com

The SMTP client at gonzo.gov connects to the http://whizzer.com mailer to deliver Fred's copy. When it's ready to list the recipients (the envelope address), what should it say? If it gives both recipients as they are listed in the preceding To: line (the header address), Betty will get two copies of the letter because the http://whizzer.com mailer will forward a copy to zippy.gov. The same problem occurs if the gonzo.gov SMTP client connects to zippy.gov and lists both Betty and Fred as recipients. The zippy.gov mailer will forward a second copy of Fred's letter.

The solution is the same one that Alphonse and the other mail clerks used. The gonzo.gov SMTP client puts the letter in an envelope containing only the names of the recipients on each host. The complete recipient list is still in the letter's headers, but they are inside the envelope and the SMTP servers at gonzo.gov and http://whizzer.com don't look at them. In this example, the envelope for the http://whizzer.com mailer lists only fred, and the envelope for zippy.gov lists only betty.

Aliases illustrate another reason that header and envelope addresses differ. Suppose you send mail to the alias homeboys, which includes the names alphonse, joe, betty, and george. In your letter, you write To: homeboys. However, sendmail expands the alias and constructs an envelope that includes all the recipients. Depending on whether the names are also aliases, perhaps on other hosts, the original message might be put into as many as four different envelopes and delivered to four different hosts. In each case, the envelope contains only the names of the recipients, but the original message contains the alias homeboys (expanded to homeboys@ your.host.domain so replies will work).

A final example shows another way in which envelope addresses might differ from header addresses. With sendmail, you can specify recipients on the command line. Suppose you have a file named letter that looks like this:

$ cat letter
To: null recipient <>
Subject: header and envelope addresses

testing

You send this letter with the following command, substituting your own login name for yourlogin :

$ /usr/sbin/sendmail yourlogin < letter

Because your address was on the envelope, you will receive the letter even though your login name doesn't appear in the letter's headers. Unless it's told otherwise (with the -t flag), sendmail constructs envelope addresses from the recipients you specify on the command line, and a correspondence doesn't necessarily exist between the header addresses and the envelope addresses.

sendmail's Jobs

To better understand how to set up sendmail, you need to know what jobs it does and how these jobs fit into the scheme of MUAs, MTAs, mail routers, final delivery agents, and SMTP clients and servers. sendmail can act as a mail router, an SMTP client, and an SMTP server. However, it does not do final delivery of mail.

sendmail as Mail Router

sendmail is primarily a mail router, meaning that it takes a letter, inspects the recipient addresses, and decides the best way to send it. How does sendmail perform this task?

sendmail determines some of the information it needs on its own, such as the current time and the name of the host on which it's running, but most of its brains are supplied by you, the postmaster, in the form of a configuration file, sendmail.cf (described in more detail later). This somewhat cryptic file tells sendmail exactly how you want various kinds of mail handled. sendmail.cf is extremely flexible and powerful, and seemingly inscrutable at first glance. However, one of the strengths of V.8 sendmail is its set of modular configuration file building blocks. Most sites can easily construct their configuration files from these modules, and many examples are included. Writing a configuration file from scratch is a daunting task, so you should avoid it if at all possible!

sendmail as MTA: Client (Sender) and Server (Receiver) SMTP

As mentioned before, sendmail can function as an MTA because it understands the SMTP protocol (V.8 sendmail also understands ESMTP). SMTP is a connection-oriented protocol, so a client and a server (also known as a sender and a receiver) always exist. The SMTP client delivers a letter to an SMTP server, which listens continuously on its computer's SMTP port. sendmail can be an SMTP client or an SMTP server. When run by an MUA, it becomes an SMTP client and speaks client-side SMTP to an SMTP server (not necessarily another sendmail program). When your sendmail starts in daemon mode, it runs as a server. When in this server mode it does two main tasks. The first is to continuously listen on the SMTP port for incoming mail. The second is to manage the queue of mail that has not been delivered yet and to periodically retry delivery until the message is finally delivered successfully or the retry limit is exceeded.

sendmail Is Not a Final Delivery Agent

One thing that sendmail doesn't do is final delivery. sendmail's author wisely chose to leave this task to other programs. sendmail is a big, complicated program that runs with superuser privileges. That's an almost guaranteed recipe for security problems, and quite a few have occurred in sendmail's past. The additional complexity of final mail delivery is the last thing sendmail needs. By default on Red Hat systems, procmail is used as the local delivery agent.

sendmail's Auxiliary Files

sendmail depends on a number of auxiliary files to do its job. Most important are the aliases file and the configuration file, sendmail.cf. The statistics file, sendmail.st, can be created or not, depending on whether you want statistics on how many messages are sent to and received from your host. This includes the total amount of email traffic in kilobytes as well. sendmail.hf, which is the SMTP help file, should be installed if you intend to run sendmail as an SMTP server (most sites do).

The other file that might be required on your host is sendmail.cw, which contains all of the alternate hostnames for your email server. For example, if your main email server is http://mail.whizzer.com, which is specified as an MX for http://whizzer.com, you would need to put http://whizzer.com in this file to tell sendmail to deliver http://whizzer.com email on http://mail.whizzer.com.

That's all that needs to be said about sendmail.st, sendmail.hf, and sendmail.cw. Other auxiliary files are covered in the Sendmail Installation and Operating Guide, or SIOG for short. The SIOG is usually found in /usr/share/doc/sendmail/doc/op/ op.ps, which comes from the sendmail-doc RPM or in the source distribution of sendmail. The aliases and sendmail.cf files, on the other hand, are important enough to be covered in their own sections.

The Aliases File

sendmail always checks recipient addresses for aliases, which are alternative names for recipients. For example, each Internet site is required to have a valid address postmaster to whom mail problems can be reported. Most sites don't have an actual account of that name but divert the postmaster's mail to the person or persons responsible for email administration. For example, at the fictional site gonzo.gov, the users joe and betty are jointly responsible for email administration, and the aliases file has the following entry:

postmaster: joe, betty

This line tells sendmail that mail to postmaster should instead be delivered to the login names joe and betty. In fact, these names could also be aliases:

postmaster: firstshiftops, secondshiftops, thirdshiftops
firstshiftops: joe, betty
secondshiftops: lou, emma
thirdshiftops: ben, mark, clara

In all these examples, the alias names are on the left side of the colon and the aliases for those names are on the right side. sendmail repeatedly evaluates aliases until they resolve to a real user or a remote address. To resolve the alias postmaster in the preceding example, sendmail first expands it into the list of recipients—firstshiftops, secondshiftops, and thirdshiftops—and then expands each of these aliases into the final list—joe, betty, lou, emma, ben, mark, and clara.

Although the right side of an alias can refer to a remote host, the left side cannot. The alias joe: joe@whizzer.com is legal, but joe@gonzo.gov: joe@whizzer.com is not.

Whenever you modify the alias file, you must run the command newaliases. Otherwise, sendmail will not know about the changes.

Reading Aliases from a File: The :include: Directive

Aliases can be used to create mailing lists. (In the example shown in the preceding section, the alias postmaster is, in effect, a mailing list for the local postmasters.) For big or frequently changing lists, you can use the :include: alias form to direct sendmail to read the list members from a file. Assume the aliases file contains this line:

homeboys: :include:/home/alphonse/homeboys.aliases

Assume also that the file /home/alphonse/homeboys.aliases contains this:

alphonse
joe
betty
george

The effect is the same as this alias:

homeboys: alphonse, joe, betty, george

This directive is handy for mailing lists that are automatically generated, change frequently, or are managed by users other than the postmaster. If you find that a user is asking for frequent changes to a mail alias, you might want to put it under her control. You must be careful; the latest versions of sendmail are very picky with permissions of files that they reference. If any of these files or parent directories have group or world writable permissions, the files will most likely be ignored, which might cause sendmail to cease working or not even start at all. These sorts of problems are usually logged to your system messages file (/var/log/messages or /var/log/maillog, depending on how your syslog is configured).

Mail to Programs

The aliases file can also be used to send the contents of email to a program. For example, many mailing lists are set up so you can get information about the list or subscribe to it by sending a letter to a special address, list -request. The letter usually contains a single word in its body, such as help or subscribe, which causes a program to mail an information file to the sender. Suppose the gonzo mailing list has such an address, called gonzo-request:

gonzo-request: |/usr/local/lib/auto-gonzo-reply

In this form of alias, the pipe symbol (|) tells sendmail to use the program mailer, which is usually defined as /bin/sh (see The M Operator: Mailer Definitions later in this chapter). sendmail feeds the message to the standard input of /usr/local/lib/ auto-gonzo-reply, and if it exits normally, sendmail considers the letter to be delivered.

Mail to Files

You can also create an alias that causes sendmail to send mail to files. This sort of alias begins with a forward slash (/), which will be a full pathname to the file you want to append to. An example is the alias nobody, which is common on systems running the Network File System (NFS):

nobody: /dev/null

Aliases that specify files cause sendmail to append its message to the named file. Because the special file /dev/null is the UNIX bit-bucket, this alias simply throws mail away.

Setting Up sendmail

The easiest way to show you how to set up sendmail is to use a concrete example.

To summarize, first, you must install the included sendmail RPM package as well as the sendmail-cf package that installs all the files required to build your own configuration file. Next, choose a sendmail.mc file that closely models your site's requirements and tinker with it as necessary. The .mc files use a series of m4 macros, which will be covered later, to simplify the creation of the rather dense sendmail.cf file. To make the sendmail.cf from the .mc file you've modified, use the make utility. Then test sendmail and its configuration file. Finally, install sendmail.cf and other auxiliary files.

The preceding are the basic steps, but you might also have to make sure that sendmail is configured to start correctly when your system reboots. The easiest way to do this is to run the control-panel program as root. Then select the icon that looks like two traffic light symbols. This is the Runlevel editor and is shown in Figure 10.1.

10fig01.gif

Figure 10.1 The Red Hat control-panel.

After you click the Runlevel editor, you will see a number of runlevels as displayed in Figure 10.2. Make sure sendmail is located in all runlevels that you require it in. By default it should be in all of those displayed. If it isn't, just put it in Runlevel 3 for now by clicking in the leftmost window, scrolling down to sendmail, selecting it, and then clicking Add and selecting Runlevel 3.

10fig02.jpg

Figure 10.2 The Runlevel editor.

In addition, you must create an aliases file if your system doesn't already have one. In a Red Hat system it will be /etc/aliases, but some systems might locate it in /usr/lib/ aliases depending on your version of UNIX. The location of the aliases file is given in sendmail.cf, so you can put it wherever you want. You might also have to make changes to your system's DNS database, but that information is not covered here (see Chapter 20). Future versions of sendmail will place all ancillary sendmail files into the /etc/mail directory.

Obtaining the Source

Red Hat Linux ships with sendmail 8.10.1. Fortunately, this is the latest version at the time of this writing. If you are concerned with security (and you should be), you will want to keep track of any new versions by checking the comp.security.announce newsgroup regularly. The latest version of sendmail is always found at http://www.sendmail.org. New versions or patches are quickly brought out when a security flaw is found, and you should upgrade your own system as soon as possible after a new version is released. It would be wise to wait for a Red Hat RPM to be released with the new patches already applied; otherwise you need to get the patches and apply them to the source as well as the other Red Hat configuration changes. This process is not trivial. Check ftp://updates.redhat.com/7.0/i386 or the various Red Hat mirror sites around the world for any Red Hat RPM updates.

Note that the exact names of the files to download differ depending on the most current version of sendmail. In the case of the sendmail included in Red Hat 7 the sendmail RPM is called sendmail-8.11.0-8.i386.rpm. Also, because the files are compressed, you must give FTP the binary command before transferring them. Note too that you should include your complete email address as the FTP password—for example, mylogin@gonzo.gov.

Unpacking the Source and Compiling sendmail

You need to read this section only if there is a new version of sendmail that hasn't been released as an RPM yet and you need new features or bug fixes in place immediately. I assume you have downloaded the source from ftp://ftp.sendmail.org.

Now that you have the source, you need to unpack it. Because it's a compressed tar image, you must first decompress it and then extract the individual files from the tar archive. An example command to do this is

[root@gonzo src]# tar zxvf sendmail-8.10.1.tar.gz

Now you're almost ready to compile sendmail. But first read the following files, which contain the latest news about the specific release of sendmail you've downloaded:

     RELEASE_NOTES
     KNOWNBUGS
     README

You might also want to check the Sendmail Frequently Asked Questions (FAQ) located at http://www.sendmail.org/faq. This is a useful source of information on common configuration mistakes or questions on how to set up a particular configuration.

Also take note that the Sendmail Installation and Operation Guide (SIOG) is in the doc/op subdirectory.

Now run cd and ls to see what files are in the source directory:

[root@gonzo src]# cd sendmail-8.11.0/src
[root@gonzo src]# ls
Makefile      collect.c     macro.c       parseaddr.c   srvrsmtp.c
Makefiles     conf.c        mailq.0       pathnames.h   stab.c
READ_ME       conf.h        mailq.1       queue.c       stats.c
TRACEFLAGS    convtime.c    mailstats.h   readcf.c      sysexits.c
alias.c       daemon.c      main.c        recipient.c   sysexits.h
aliases       deliver.c     makesendmail  safefile.c    trace.c
aliases.0     domain.c      map.c         savemail.c    udb.c
aliases.5     envelope.c    mci.c         sendmail.0    useful.h
arpadate.c    err.c         mime.c        sendmail.8    usersmtp.c
cdefs.h       headers.c     newaliases.0  sendmail.h    util.c
clock.c       ldap_map.h    newaliases.1  sendmail.hf   version.c

Thankfully, Eric Allman and the sendmail crew have done a fantastic job of making the installation process very straightforward. To compile your new version of sendmail, simply run the following (from the sendmail src directory):

[root@gonzo src]# ./Build

And then watch it build.

This creates a directory obj.* that contains the result of the compilation (so you can build sendmail for different machines or operating systems in the same sources). Also check the BuildTools/Site and BuildTools/OS directories for further configuration.

To install the new version of the sendmail executable, first stop the currently running daemon with the following command:


   [root@gonzo src]# /etc/rc.d/init.d/sendmail stop

Then type this:


   [root@gonzo src]# ./Build install

With everything in place, you can restart the new daemon with the following:


   [root@gonzo src]# /etc/rc.d/init.d/sendmail restart

sendmail.cf: The Configuration File

With the advent of V.8, sendmail has shipped with a quick and easy way to automatically create a sendmail.cf file for you. In fact, it is highly recommended that you do not create or modify any sendmail.cf files manually. You can safely skip this section if you aren't interested in the gory details regarding the sendmail.cf file. (I discuss the easy way to configure sendmail in the next section.)

The sendmail.cf file provides sendmail with its brains, and because it's so important, this section covers it in fairly excruciating detail. Don't worry if you don't understand everything in this section the first time through. It will make more sense upon rereading and after you've had a chance to play with some configuration files of your own.

sendmail's power lies in its flexibility, which comes from its configuration file, sendmail.cf. sendmail.cf statements compose a cryptic programming language that doesn't inspire much confidence at first glance (but C language code probably didn't either, the first time you saw it). However, learning the sendmail.cf language isn't very hard, and you won't have to learn the nitty-gritty details unless you plan to write a sendmail.cf from scratch—a bad idea at best.

General Form of the Configuration File

Each line of the configuration file begins with a single command character that indicates the function and syntax of that line. Lines beginning with a # are comments, and blank lines are ignored. Lines beginning with a space or tab are continuations of the preceding line, although you should usually avoid continuations.

Table 10.1 shows the command characters and their functions as well as an example of their usage. This table is split into three parts corresponding to the three main functions of a configuration file, which are covered later in the section "A Functional Description of the Configuration File."

Table 10.1. sendmail.cf Command Characters

Command Character Command Syntax and Example Function
# # comments are ignored A comment line. Always use lots of comments.
  # Standard RFC822 parsing  
D D X string Defines a macro X to have the string value string.
  DMmailhub.gonzo.gov  
D D{ MacroName} value Defines long macro { MacroName} to have the value, value, then referenced later with ${ MacroName}.
  D{ Relay} mailhub.gonzo.gov  
C CX word1, word2, and so on Defines a classX as word1, word2, and so on.
  Cwlocalhost myuucpname  
F FX /path/to/a/file Defines a class X by reading it from a file.
  Fw/etc/mail/host_aliases  
H H? mailerflag ? name:template Defines a mail header.
  H?F?From: $q  
O OX option arguments Sets option X. Most command-line options can be set in sendmail.cf.
  OL9 # sets the log level to 9.  
P Pclass= nn Sets mail delivery precedence based on the class of the mail.
  Pjunk=-100  
V V n Tells V.8 sendmail the version level of the configuration file.
  V3  
K K name class arguments Defines a key file (database map).
  Kuucphosts hash /etc/mail/uucphsts  
M M name,field_1=value_1, Defines a mailer.
  Mprog,P=/bin/sh,F=lsD, 0A=sh -c $u  
S S nn Begins a new rule set.
  S22  
R R lhs rhs comment Defines a matching/rewriting rule.
  R$+ $:$>22 call ruleset 22  

A Functional Description of the Configuration File

A configuration file does three things. First, it sets the environment for sendmail by telling it which options you want set and the locations of the files and databases it uses.

Second, a configuration file defines the characteristics of the mailers (delivery agents or MTAs) that sendmail uses after it decides where to route a letter. All configuration files must define local and program mailers to handle delivery to users on the local host, most of them also define one or more SMTP mailers, and sites that must handle UUCP mail define UUCP mailers.

Third, a configuration file specifies rulesets that rewrite sender and recipient addresses and select mailers. All rulesets are user-defined, but some have special meaning to sendmail. Ruleset 0, for example, is used to select a mailer. Rulesets 0, 1, 2, 3, and 4 all have special meaning to sendmail and are processed in a particular order (see the section The S and R Operators: Rulesets and Rewriting Rules later in this chapter).

The following sections cover the operators in more detail, in the order in which they appear in Table 10.1.

The D Operator: Macros

Macros are like shell variables. After you define a macro's value, you can refer to it later in the configuration file and its value will be substituted for the macro. For example, a configuration file might have many lines that mention the hypothetical mail hub mailer.gonzo.gov. Rather than type that name over and over, you can define a macro R (for relay mailer) as follows:

DRmailer.gonzo.gov

When sendmail encounters an $R in sendmail.cf, it substitutes the string mailer.gonzo.gov.

Macro names can be more than one character. You could, for example, define

D{Relay}mailer.gonzo.gov

then refer to it later with

${Relay}

Quite a few macros are defined by sendmail and shouldn't be redefined except to work around broken software. sendmail uses lowercase letters for its predefined macros. Uppercase letters can be used freely. V.8 sendmail's predefined macros are fully documented in section 5.1.2 of the SIOG.

The C and F Operators: Classes

Classes are similar to macros but are used for different purposes in rewriting rules (see The S and R Operators: Rulesets and Rewriting Rules later in this chapter). As with macros, classes are named by single characters. Lowercase letters are reserved for sendmail and uppercase letters for user-defined classes. A class contains one or more words. For example, you could define a class H containing all the hosts in the local domain as follows:

CH larry moe curly

For convenience, large classes can be continued on subsequent lines. The following definition of the class H is the same as the preceding one:

CH larry
CH moe
CH curly

You can also define a class by reading its words from a file:

CF/usr/local/lib/localhosts

If the file /usr/local/lib/localhosts contains the words larry, moe, and curly, one per line, this definition is equivalent to the preceding two.

Why use macros and classes? The best reason is that they centralize information in the configuration file. In the preceding example, if you decide to change the name of the mail hub from mailer.gonzo.gov to mailhub.gonzo.gov, you have to change only the definition of the $R macro remedy for the configuration file to work as before. If the name mailer.gonzo.gov is scattered throughout the file, you might forget to change it in some places. Also, if important information is centralized, you can comment it extensively in a single place. Because configuration files tend to be obscure at best, a liberal dose of comments is a good antidote to that sinking feeling you get six months later, when you wonder why you made a change.

The H Operator: Header Definitions

You probably won't want to change the header definitions given in the V.8 sendmail configuration files because they already follow accepted standards. Here are some sample headers:

H?D?Date: $a
H?F?Resent-From: $q
H?F?From: $q
H?x?Full-Name: $x

Note that header definitions can use macros, which are expanded when inserted into a letter. For example, the $x macro used in the preceding Full-Name: header definition expands to the full name of the sender.

The optional ?mailerflag? construct tells sendmail to insert a header only if the chosen mailer has that mailer flag set (see The M Operator: Mailer Definitions later in this chapter).

Suppose the definition of your local mailer has a flag Q, and sendmail selects that mailer to deliver a letter. If your configuration file contains a header definition like the following one, sendmail inserts that header into letters delivered through the local mailer, substituting the value of the macro $F:

H?Q?X-Fruit-of-the-day: $F

Why would you use the ?mailerflag? feature? Different protocols can require different mail headers. Because they also need different mailers, you can define appropriate mailer flags for each in the mailer definition and use the ?mailerflag? construct in the header definition to tell sendmail whether to insert the header.

The O Operator: Setting Options

sendmail has many options that change its operation or tell it the location of files it uses. Most of them can be given either on the command line or in the configuration file. For example, you can specify the location of the aliases file in either place. To specify the aliases file on the command line, you use the -o option:

$ /usr/sbin/sendmail -oA/etc/aliases [other arguments...]

To do the same thing in the configuration file, you include a line like this:

OA/etc/aliases

Either use is equivalent, but options such as the location of the aliases file rarely change, and most people set them in sendmail.cf. The V.8 sendmail options are fully described in the SIOG.

The P Operator: Mail Precedence

Users can include mail headers indicating the relative importance of their mail, and sendmail can use those headers to decide the priority of competing messages. Precedences for V.8 sendmail are given as follows:

Pspecial-delivery=100
Pfirst-class=0
Plist=-30
Pbulk=-60
Pjunk=-100

If users who run large mailing lists include the header Precedence: bulk in their letters, sendmail gives them a lower priority than letters with the header Precedence: first-class.

The V Operator: sendmail.cf Version Levels

As V.8 sendmail evolves, its author adds new features. The V operator tells V.8 sendmail which features it should expect to find in your configuration file. Older versions of sendmail don't understand this command. The SIOG explains the configuration file version levels in detail.

The K Operator: Key Files

sendmail has always used keyed databases—for example, the aliases databases. Given the key postmaster, sendmail looks up the data associated with that key and returns the names of the accounts to which the postmaster's mail should be delivered. V.8 sendmail extends this concept to arbitrary databases, including NIS maps (Sun's Network Information Service, formerly known as Yellow Pages or YP; see Chapter 15, "NIS: Network Information Service," for details). The K operator tells sendmail the location of the database, its class, and how to access it. V.8 sendmail supports the following classes of user-defined databases: dbm, btree, hash, and NIS. The default used when compiling under Linux is one of the hash or btree formats. See the SIOG for the lowdown on key files.

The M Operator: Mailer Definitions

Mailers are either MTAs or final delivery agents. Recall that the aliases file enables you to send mail to a login name (which might be aliased to a remote user), a program, or a file. A special mailer can be defined for each purpose, and even though the SMTP MTA is built in, it must have a mailer definition to tailor sendmail's SMTP operations.

Mailer definitions are important because all recipient addresses must resolve to a mailer in ruleset 0. Resolving to a mailer is just another name for sendmail's main function, mail routing. For example, resolving to the local mailer routes the letter to a local user via the final delivery agent defined in that mailer (such as /bin/mail), and resolving to the SMTP mailer routes the letter to another host via sendmail's built-in SMTP transport, as defined in the SMTP mailer.

A concrete example of a mailer definition will make this information clearer. Because sendmail requires a local mailer definition, look at the following:

Mlocal, P=/bin/mail, F=lsDFMfSn, S=10, R=20, A=mail -d $u

All mailer definitions begin with the M operator and the name of the mailer—in this case, local. Other fields follow, separated by commas. Each field consists of a field name and its value, separated by an equal sign (=). The allowable fields are explained in section 5.1.4 of the SIOG.

In the preceding local mailer definition, the P= equivalence gives the pathname of the program to run to deliver the mail, /bin/mail. The F= field gives the sendmail flags for the local mailer (see also The H Operator: Header Definitions earlier in the chapter.) These flags are not passed to the command mentioned in the P= field but are used by sendmail to modify its operation, depending on the mailer it chooses. For example, sendmail usually drops its superuser status before invoking mailers, but you can use the S mailer flag to tell sendmail to retain this status for certain mailers.

The S= and R= fields specify rulesets for sendmail to use in rewriting sender and recipient addresses. Because you can give different R= and S= flags for each mailer you define, you can rewrite addresses differently for each mailer. For example, if one of your UUCP neighbors runs obsolete software that doesn't understand domain addressing, you might declare a special mailer just for that site and write mailer-specific rulesets to convert addresses into a form its mailer can understand.

The S= and R= fields can also specify different rulesets to rewrite the envelope and header addresses . A specification such as S=21/31 tells sendmail to use ruleset 21 to rewrite sender envelope addresses and ruleset 31 to rewrite sender header addresses. This capability comes in handy for mailers that require addresses to be presented differently in the envelope than in the headers.

The A= field gives the argument vector (command line) for the program that will be run—in this case, /bin/mail. In this example, sendmail runs the command as mail -d $u, expanding the $u macro to the name of the user to whom the mail should be delivered:

/bin/mail -d joe

You could type this same expanded command to your shell at a command prompt.

You might want to use many other mailer flags to tune mailers—for example, to limit the maximum message size on a per-mailer basis. These flags are all documented in section 5.1.4 of the SIOG.

The S and R Operators: Rulesets and Rewriting Rules

A configuration file is composed of a series of rulesets, which are somewhat like subroutines in a program. Rulesets are used to detect bad addresses, to rewrite addresses into forms that remote mailers can understand, and to route mail to one of sendmail's internal mailers (see the previous section, The M Operator: Mailer Definitions).

sendmail passes addresses to rulesets according to a built-in order. Rulesets also can call other rulesets not in the built-in order. The built-in order varies depending on whether the address being handled is a sender or receiver address and which mailer has been chosen to deliver the letter.

Rulesets are announced by the S command, which is followed by a number to identify the ruleset. sendmail collects subsequent R (rule) lines until it finds another S operator or the end of the configuration file. The following example defines ruleset 11:

# Ruleset 11
S11
R$+       $: $>22 $1     call ruleset 22

This ruleset doesn't do much that is useful. The important point to note is that sendmail collects ruleset number 11, which is composed of a single rule.

sendmail's Built-In Ruleset Processing Rules

sendmail uses a three-track approach to processing addresses: one to choose a delivery agent, another to process sender addresses, and another for receiver addresses.

All addresses are first sent through ruleset 3 for preprocessing into a canonical form that makes them easy for other rulesets to handle. Regardless of the complexity of the address, ruleset 3's job is to decide the next host to which a letter should be sent. Ruleset 3 tries to locate that host in the address and mark it within angle brackets. In the simplest case, an address like joe@gonzo.gov becomes joe<@gonzo.gov>.

Ruleset 0 then determines the correct delivery agent (mailer) to use for each recipient. For example, a letter from betty@whizzer.com to joe@gonzo.gov (an Internet site) and pinhead!zippy (an old-style UUCP site) requires two different mailers: an SMTP mailer for gonzo.gov and an old-style UUCP mailer for pinhead. Mailer selection determines later processing of sender and recipient addresses because the rulesets given in the S= and R= mailer flags vary from mailer to mailer.

Addresses sent through ruleset 0 must resolve to a mailer. This means that when an address matches the lhs, the rhs gives a triple of the mailer, user, and host. The rhs tells sendmail what to do with addresses that match the pattern specified by the lhs. The following line shows the syntax for a rule that resolves to a mailer:

Rlhs      $#mailer $@host $:user   your comment here...

The mailer is the name of one of the mailers you've defined in an M command—for example, smtp. The host and user are usually positional macros taken from the lhs match (see The Right-Hand Side (rhs) of Rules later in the chapter).

After sendmail selects a mailer in ruleset 0, it processes sender addresses through ruleset 1 (often empty) and then sends them to the ruleset given in the S= flag for that mailer.

Similarly, sendmail sends recipient addresses through ruleset 2 (also often empty) and then to the ruleset mentioned in the R= mailer flag.

Finally, sendmail post-processes all addresses in ruleset 4, which (among other things) removes the angle brackets inserted by ruleset 3.

Why do mailers have different S= and R= flags? Consider the previous example of the letter sent to joe@gonzo.gov and pinhead!zippy. If betty@whizzer.com sends the mail, her address must appear in a different form to each recipient. For Joe, it should be a domain address, betty@whizzer.com. For Zippy, because pinhead expects old-style UUCP addresses, the return address should be whizzer!betty. Joe's address must also be rewritten for the pinhead UUCP mailer, and Joe's copy must include an address for Zippy that his mailer can handle.

Processing Rules Within Rulesets

sendmail passes an address to a ruleset and then processes it through each rule line by line. If the lhs of a rule matches the address, it is rewritten by the rhs. If it doesn't match, sendmail continues to the next rule until it reaches the end of the ruleset. At the end of the ruleset, sendmail returns the rewritten address to the calling ruleset or to the next ruleset in its built-in execution sequence.

If an address matches the lhs and is rewritten by the rhs, the rule is tried again—an implicit loop (but see the $: and $@: Altering a Ruleset's Evaluation section for exceptions).

As shown in Table 10.1, each rewriting rule is introduced by the R command and has three fields—the left-hand side (lhs, or matching side), the right-hand side (rhs, or rewriting side), and an optional comment—which must be separated from one another by tab characters:

Rlhs      rhs       comment

Parsing: Turning Addresses into Tokens

sendmail parses addresses and the lhs of rules into tokens and then matches the address and the lhs token by token. The macro $o contains the characters that sendmail uses to separate an address into tokens. It's often defined like this:

# address delimiter characters
Do.:%@!^/[]

All the characters in $o are both token separators and tokens. sendmail takes an address such as rae@rainbow.org and breaks it into tokens according to the characters in the o macro, like this:

"rae"     "@"     "rainbow"     "."     "org"

sendmail also parses the lhs of rewriting rules into tokens so they can be compared one by one with the input address to see whether they match. For example, the lhs $-@rainbow.org is parsed as follows:

"$-"     "@"     "rainbow"     "."     "org"

(Don't worry about the $- just yet. It's a pattern-matching operator, similar to a shell wildcard, that matches any single token and is covered later in the section "The Left-Hand Side (lhs) of Rules.") Now you can put the two together to show how sendmail decides whether an address matches the lhs of a rule:

"rae"     "@"     "rainbow"     "."     "org"
"$-"     "@"     "rainbow"     "."     "org"

In this case, each token from the address matches with the pattern-matching operator ($-) matching rae, so the address matches and sendmail will use the rhs to rewrite the address.

Consider the effect (usually bad) of changing the value of $o. As shown previously, sendmail breaks the address rae@rainbow.org into five tokens. However, if the @ character were not in $o, the address would be parsed quite differently, into only three tokens:

"rae@rainbow"     "."     "org"

You can see that changing $o has a drastic effect on sendmail's address parsing, and you should leave it alone until you know what you're doing. Even then, you probably won't want to change it because the V.8 sendmail configuration files already have it correctly defined for standard RFC 822 and RFC 976 address interpretation.

The Left-Hand Side (lhs) of Rules

The lhs is a pattern against which sendmail matches the input address. The lhs can contain ordinary text or any of the pattern-matching operators shown in Table 10.2.

Table 10.2. lhs Pattern-Matching Operators

Operator Meaning
$- Matches exactly one token.
$+ Matches one or more tokens.
$* Matches zero or more tokens.
$@ Matches the null input (used to call the error mailer).

The values of macros and classes are matched in the lhs with the operators shown in Table 10.3.

Table 10.3. lhs Macro and Class-Matching Operators

Operator Meaning
$X Matches the value of macro X.
$=C Matches any word in class C.
$~C Matches if token is not in class C.

The pattern-, macro-, and class-matching operators are necessary because most rules must match many different input addresses. For example, a rule might need to match all addresses that end with gonzo.gov and begin with one or more of anything.

The Right-Hand Side (rhs) of Rules

The rhs of a rewriting rule tells sendmail how to rewrite an address that matches the lhs. The rhs can include text, macros, and positional references to matches in the lhs. When a pattern-matching operator from Table 10.2 matches the input, sendmail assigns it to a numeric macro $n corresponding to the position it matches in the lhs. For example, suppose the address joe@pc1.gonzo.gov is passed to the following rule:

R$+ @ $+       $: $1 < @ $2 >           focus on domain

In this example, joe matches $+ (one or more of anything), so sendmail assigns the string joe to $1. The @ in the address matches the @ in the lhs, but constant strings are not assigned to positional macros. The tokens in the string pc1.gonzo.gov match the second $+ and are assigned to $2. The address is rewritten as $1<@$2>, or joe<@pc1.gonzo.gov>.

$: and $@: Altering a Ruleset's Evaluation

Consider the following rule:

R$*  $: $1 < @ $j > add local domain

After rewriting an address in the rhs, sendmail tries to match the rewritten address with the lhs of the current rule. Because $* matches zero or more of anything, what prevents sendmail from going into an infinite loop on this rule? After all, no matter how the rhs rewrites the address, it will always match $*.

The $: preface to the rhs comes to the rescue, telling sendmail to evaluate the rule only once.

Sometimes you might want a ruleset to terminate immediately and return the address to the calling ruleset or the next ruleset in sendmail's built-in sequence. Prefacing a rule's rhs with $@ causes sendmail to exit the ruleset immediately after rewriting the address in the rhs.

$>: Calling Another Ruleset

A ruleset can pass an address to another ruleset by using the $> preface to the rhs. Consider the following rule:

R$*       $: $>66 $1          call ruleset 66

The lhs $* matches zero or more of anything, so sendmail always does the rhs. As you learned in the preceding section, the $: prevents the rule from being evaluated more than once. The $>66 $1 calls ruleset 66 with $1 as its input address. Because the $1 matches whatever was in the lhs, this rule simply passes the entirety of the current input address to ruleset 66. Whatever ruleset 66 returns is passed to the next rule in the ruleset.

Testing Rules and Rulesets: The -bt, -d, and -C Options

Debugging sendmail.cf can be a tricky business. Fortunately, sendmail provides several ways to test rulesets before you install them.

The -bt option tells sendmail to enter its rule-testing mode:

$ /usr/sbin/sendmail -bt
ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)
Enter <ruleset> <address>
>

The > prompt means sendmail is waiting for you to enter one or more ruleset numbers, separated by commas, and an address. Try your login name with rulesets 3 and 0. The result should look something like this:


   > 3,0 joe
rewrite: ruleset  3   input: joe
rewrite: ruleset  3 returns: joe
rewrite: ruleset  0   input: joe
rewrite: ruleset  3   input: joe
rewrite: ruleset  3 returns: joe
rewrite: ruleset  6   input: joe
rewrite: ruleset  6 returns: joe
rewrite: ruleset  0 returns: $# local $: joe
>

The output shows how sendmail processes the input address joe in each ruleset. Each line of output is identified with the number of the ruleset processing it, the input address, and the address that the ruleset returns. The > is a second prompt indicating that sendmail is waiting for another line of input. When you're done testing, just press Ctrl+D.

Indentation and blank lines better show the flow of processing in this example:

rewrite: ruleset  3   input: joe
rewrite: ruleset  3 returns: joe

rewrite: ruleset  0   input: joe

     rewrite: ruleset  3   input: joe
     rewrite: ruleset  3 returns: joe

     rewrite: ruleset  6   input: joe
     rewrite: ruleset  6 returns: joe

rewrite: ruleset  0 returns: $# local $: joe

The rulesets called were 3 and 0, in that order. Ruleset 3 was processed and returned the value joe, and then sendmail called ruleset 0. Ruleset 0 called ruleset 3 again and then ruleset 6, an example of how a ruleset can call another one by using $>. Neither ruleset 3 nor ruleset 6 rewrote the input address. Finally, ruleset 0 resolved to a mailer, as it must.

Often you need more detail than -bt provides—usually just before you tear out a large handful of hair because you don't understand why an address doesn't match the lhs of a rule. You can remain hirsute because sendmail has verbose debugging built into most of its code.

You use the -d option to turn on sendmail's verbose debugging. This option is followed by a numeric code that indicates which section of debugging code to turn on and at what level. The following example shows how to run sendmail in one of its debugging modes and the output it produces:

$ /usr/sbin/sendmail -bt -d21.12
ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)
Enter <ruleset> <address>
> 3,0 joe
rewrite: ruleset  3   input: joe
--trying rule: $* < > $*
-- rule fails
--trying rule: $* < $* < $* < $+ > $* > $* > $*
-- rule fails
[etc.]

The -d21.12 in the preceding example tells sendmail to turn on level 12 debugging in section 21 of its code. The same command with the option -d21.36 gives more verbose output (debug level 36 instead of 12).

The -d option is not limited to use with sendmail's address testing mode (-bt). You can also use it to see how sendmail processes rulesets while sending a letter, as the following example shows:

$ /usr/sbin/sendmail -d21.36 joe@gonzo.gov < /tmp/letter
[lots and lots of output...]

Unfortunately, the SIOG doesn't tell you which numbers correspond to which sections of code. Instead, the author suggests that keeping such documentation current is a lot of work (which it is), and that you should look at the code itself to discover the correct debugging formulas.

The function tTd() is the one to look for. For example, suppose you want to turn on debugging in sendmail's address-parsing code. The source file parseaddr.c contains most of this code, and the following command finds the allowable debugging levels:

$ egrep tTd parseaddr.c
        if (tTd(20, 1))
[...]
        if (tTd(24, 4))
        if (tTd(22, 11))
[etc.]

The egrep output shows that debugging specifications such as -d20.1, -d24.4, and -d22.11 (and others) will make sense to sendmail.

If perusing thousands of lines of C code doesn't appeal to you, the O'Reilly book, sendmail, Second Edition, documents the debugging flags for sendmail. Note that the book only covers up to sendmail-8.8; small differences in detail could exist but it is still a good reference.

The -C option enables you to test new configuration files before you install them, which is always a good idea. If you want to test a different file, use -C /path/to/the/file. You can combine it with the -bt and -d flags. For example, a common invocation for testing new configuration files is

/usr/sbin/sendmail -Ctest.cf -bt -d21.12

Automatically Generating the sendmail.cf File

Luckily, these days no one has to manually edit a sendmail.cf file. Enter the following command:

[root@gonzo / ]# rpm -q sendmail-cf
sendmail-cf-8.11.0-8

If you get similar output, your configuration and macro files are already installed under the directory /usr/lib/sendmail-cf. Otherwise, you will have to install the relevant RPM from your Red Hat CD-ROMs or download the RPM from the Red Hat FTP site (ftp://ftp.redhat.com) or one of the many mirrors around the world.

A master Makefile exists in /usr/lib/sendmail-cf/cf, which makes a sendmail.cf file from a sendmail.mc file using the m4 macro processor. The mc file is what is edited to create your site-specific sendmail.cf file. You will need to check that you have the m4 package installed:

[root@gonzo /]# rpm -q m4
m4-1.4.1-3

If you get output similar to this (you might have different version numbers, but that's okay), m4 is available on your system. Otherwise, the m4 RPM will be on your Red Hat CD-ROMs.

The /usr/lib/sendmail-cf directory will look something like this:

[root@gonzo /usr/lib]# ls sendmail-cf/
README        cf            feature       m4            ostype        siteconfig
README.check  domain        hack          mailer        sh

The README file is worth reading. It contains information on the different features that you can add into your mc file, as well as other important information, including a description of the anti-spam features that have made it into the later versions of sendmail.

Creating a sendmail.cf for your site is a matter of changing to the cf directory and selecting an appropriate template. The ls should produce a listing similar to

[root@gonzo /usr/lib/sendmail-cf]# cd cf
[root@gonzo /usr/lib/sendmail-cf/cf]#  ls
Makefile                generic-hpux10.mc       obj
Makefile.dist           generic-hpux9.mc        python.cs.mc
chez.cs.mc              generic-nextstep3.3.mc  redhat.cf
clientproto.mc          generic-osf1.mc         redhat.mc
cs-hpux10.mc            generic-solaris2.mc     s2k-osf1.mc
cs-hpux9.mc             generic-sunos4.1.mc     s2k-ultrix4.mc
cs-osf1.mc              generic-ultrix4.mc      tcpproto.mc
cs-solaris2.mc          huginn.cs.mc            ucbarpa.mc
cs-sunos4.1.mc          knecht.mc               ucbvax.mc
cs-ultrix4.mc           mail.cs.mc              uucpproto.mc
cyrusproto.mc           mail.eecs.mc            vangogh.cs.mc
generic-bsd4.4.mc       mailspool.cs.mc

These are all the different mc files you can choose from to create your cf file. The redhat.mc file is the one you probably should edit. I suggest copying it to another name:

[root@gonzo /usr/lib/sendmail-cf/cf]# cp redhat.mc gonzo.mc

I will now give you a brief explanation of the various parts of this sample mc file:

divert(-1)
include(`../m4/cf.m4`)

These are directives that the m4 processor needs to process the file. You will find similar entries in some of the other mc files.

define(`confDEF_USER_ID`,``8:12``)
OSTYPE(`linux`)
undefine(`UUCP_RELAY`)
undefine(`BITNET_RELAY`)

The define indicates that you want to change a setting in sendmail, such as maximum hops allowed for a message or the maximum message size. In this case you're defining which UID and group to run the sendmail program as while it is not in privileged mode (running as root). All possible parameters you can define are listed in the README file.

Different UNIX operating systems have different conventions for where to place files and which flags to give mailers. This is what the OSTYPE macro is for. In the example, sendmail should use the Linux conventions for file locations.

The two undefines remove the capability for this sendmail host to accept UUCP and BITNET addressed mail.

FEATURE(redirect)
FEATURE(always_add_domain)
FEATURE(use_cw_file)
FEATURE(local_procmail)

The FEATURE macros allow you to add the various sendmail features that your site requires.

The redirect feature rejects all mail addressed to address.REDIRECT with a 551 User not local; please try <address> message. That way, if Joe leaves the Gonzo company to go to Whizzer Inc., the email administrator at Gonzo can alias Joe to joe@whizzer.com.REDIRECT as a courtesy so Joe's friends and work contacts can reach him at his new job.

The second feature, always_add_domain, always appends the fully qualified domain name of the local host, even on locally delivered mail whose To: address is unqualified. For example, if I address mail to joe instead of joe@gonzo.gov, sendmail will automatically append @gonzo.gov to the To: header before delivery.

The use_cw_file feature tells sendmail to look in the file /etc/sendmail.cw for alternate names for the local host. For example, if gonzo.gov also is a primary MX for the hiking club, hikers.org, both gonzo.gov and hikers.org will have entries in the sendmail.cw file.

The next feature indicates that procmail is to be used as the local mailer:

MAILER(procmail)
MAILER(smtp)

The two MAILER lines define only two mailers, procmail and SMTP. Remember, procmail was defined to be used as the local mailer. It must be defined here also, and SMTP is undefined as the mailer for remote mail deliveries.

HACK(check_mail3,`hash -a@JUNK /etc/mail/deny`)
HACK(use_ip,`/etc/mail/ip_allow`)
HACK(use_names,`/etc/mail/name_allow`)
HACK(use_relayto,`/etc/mail/relay_allow`)
HACK(check_rcpt4)
HACK(check_relay3)

As of the V8.9 series of sendmail, relaying by external hosts is denied by default. This is to stop other hosts from using your mailhost as a relay point for distributing junk mail (spam) or for other purposes. The HACKs allow you to specify which hosts are allowed to use your mail server as a relay point and which machines on the Internet to never accept email from. This is especially handy if you and your users keep getting spam from the same hosts. Read the /usr/lib/sendmail-cf/README.check file, which describes all the available HACKs and how to use them.

As you can see, the supplied redhat.mc file provides a fairly good template for your own mc file. You have already copied it to gonzo.mc. All you need to do now is add two more items and then you can create the cf file sendmail can use. Add the following after the list of FEATUREs:

FEATURE(masquerade_envelope)
MASQUERADE_AS(gonzo.gov)

These lines assume that your Gonzo mail host is called mail.gonzo.gov. Without these lines, all email you send out from your mail host will have a From: address in the envelope and message body that looks something like joe@mail.gonzo.gov. It would be nice to hide which host you sent the mail from and have the recipient From: address read something like joe@gonzo.gov. That is what the MASQUERADE_AS line does. The masquerade_envelope feature causes the message envelope From: header to be similarly masqueraded.

All that you need to do now is build the sendmail configuration file:

[root@gondor cf]# make gonzo.cf
rm -f gondor.cf
m4 ../m4/cf.m4 gondor.mc > gonzo.cf
chmod 444 gonzo.cf

If you are using GNU Make, which is almost certainly the case if you are running Red Hat, you will get an error after typing in the make command. Try make -f Makefile.dist gonzo.cf instead. If the make is successful, a gondor.cf file will appear in your cf directory. Congratulations, you have created your very first sendmail.cf file!

And After All That an Even Easier Method Still

A frequent comment in Perl circles is "there's more than one way to do it." It's yet another way Perl shows its roots so I offer one last method for configuring sendmail courtesy of the hard work of Donncha O Caoimh of the Irish Linux Users Group (http://www.linux.ie/). His installsendmail script is available at http://cork.linux.ie/projects/install-sendmail/ and works by asking users (you'll be prompted for the root password when it's time to update system files, but don't run it as root) a series of questions to configure their systems according to their needs. There are informative README and INSTALL files included and they should be read before using the script. A sample session with the version from March 13, 2000 follows:

[kevin@moo kevin]$ wget http://cork.linux.ie/projects/ install-sendmail/install-sendmail-5.3.1.tar.gz
--21:18:24--  http://cork.linux.ie:80/projects/install-sendmail/ install-sendmail-5.3.1.tar.gz

           => `install-sendmail-5.3.1.tar.gz`
Connecting to cork.linux.ie:80... connected!
HTTP request sent, awaiting response... 200 OK
Length: 39,807 [application/x-tar]

    0K -> .......... .......... .......... ........              [100%]

21:18:30 (7.78 KB/s) - `install-sendmail-5.3.1.tar.gz` saved [39807/39807]

[kevin@moo kevin]$ cp ~kevin/install-sendmail-5.3.1.tar.gz .
[kevin@moo kevin]$ tar zxf install-sendmail-5.3.1.tar.gz
[kevin@moo kevin]$ cd install-sendmail-5.3.1
[kevin@moo install-sendmail-5.3.1]$ ./install-sendmail -c

It then asks the following questions:

Which language do you wish to use? English(1)
1.1 What address do you want all the emails from your machine to have? gonzo.gov
1.2 Will all mail for gonzo.gov come to this machine? n
2.1 Do you want your outgoing email to be sent via an outside email server?
If you're on a modem dial-up connection you probably should say Y here. y
2.1.1 Where do you send your email? (outgoing smtp server, probably your ISP)
[smtp.isp.com]? mail.gonzo.gov
2.2. Queue remote mail? If you have a dial-up connection, you can compose mail
when you're offline, then "queue" it for delivery when you're connected.
(You'll have to run "usr/bin/sendmail -q" to deliver the mail, however.)
Local mail (mail to people who login to your machine) will still be delivered
as normal. If you answer "no" to this question, all mail will be delivered
immediately, rather than queued. This might cause your machine to dial-up your
connection, even at peak times.
Would you like to queue remote mail? y
3.1 Will you be serving mail to a local network? n
4. Virtual Domain Support
4.1 Do you need this feature? I'll provide a way for you to
enter aliases too. n
5. Generics Table Support
5.1 Do you want to map local email addresses to new ones? y
5.1.1 Enter the local username you want to map.
Type "none" when you're finished.
[bob]? kevin
5.1.1 What address should people see when veep writes an email?
[dennis@someplace.org]? caimhin@gonzo.gov
5.1.2 Enter the local username you want to map.
Type "none" when you're finished.
[]? none
6. Incoming Mail Servers
6.1 Do you want Fetchmail support? y
6. Incoming Mail Servers

6.1.1 Enter a pop server you poll for mail. Type "none" when you're finished.
[pop.isp.com]? pop.gonzo.gov

6.1.2 What username do you use to login to pop.gonzo.gov?
[alan]? caoimhin
6.1.3 What password do you use to login to pop.gonzo.gov?
[password]? moo
6.1.4 What user should receive the mail for caoimhin?
[bob]? kevin
6.1.5 What protocol does pop.gonzo.gov use? (POP3, IMAP, AUTO)
[pop3]? imap
6.1.2 Enter a pop server you poll for mail. Type "none" when you're finished.
[pop.telebot.com]? none

At this point it will ask for the root password to install the files. Afterwards you should restart sendmail with

/etc/init.d/sendmail restart

This is an excellent tool for users new to sendmail on home systems. The previous sections cover the methods that should be used by admins of corporate and university systems.

Testing sendmail and sendmail.cf

Before you install a new or modified sendmail.cf, you must test it thoroughly. Even small, apparently innocuous changes can lead to disaster, and people get really irate when you mess up the mail system.

The first step in testing is to create a list of addresses that you know should work at your site. For example, at gonzo.gov, an Internet site without UUCP connections, the following addresses must work:

joe
joe@pc1.gonzo.gov
joe@gonzo.gov

If gonzo.gov has a UUCP link, those addresses must also be tested. Other addresses to consider include the various kinds of aliases (for example, postmaster, an :include: list, an alias that mails to a file, and one that mails to a program), nonlocal addresses, source-routed addresses, and so on. If you want to be thorough, you can create a test address for each legal address format in RFC 822.

Now that you have your list of test addresses, you can use the -C and -bt options to see what happens. At a minimum, you should run the addresses through rulesets 3 and 0 to make sure they are routed to the correct mailer. An easy way to do so is to create a file containing the ruleset invocations and test addresses and then run sendmail on it. For example, if the file addr.test contains the lines

001 3,0 joe
002 3,0 joe@pc1.gonzo.gov
003 3,0 joe@gonzo.gov
004 

you can test your configuration file test.cf by typing


   $ /usr/sbin/sendmail -Ctest.cf -bt < addr.test
rewrite: ruleset  3   input: joe
rewrite: ruleset  3 returns: joe
[etc.]

You also might want to follow one or more addresses through the complete rewriting process. For example, if an address resolves to the smtp mailer and that mailer specifies R=21, you can test recipient address rewriting by using 3,2,21,4 test_address.

If the sendmail.cf appears to work correctly so far, you're ready to move on to sending some real letters. You can do so by using a command like the following:


   $ /usr/sbin/sendmail -v -oQ/tmp -Ctest.cf recipient < /dev/null

The -v option tells sendmail to be verbose so you can see what's happening. Depending on whether the delivery is local or remote, you can see something as simple as joe... Sent or an entire SMTP dialog. The -o sets an option that overrides what is in the sendmail.cf file. You can also use -O for long options.

The -oQ/tmp tells sendmail to use /tmp as its queue directory. Using this option is necessary because sendmail drops its superuser permissions when run with the -C option and can't write queue files into the normal mail queue directory. Because you are using the -C and -oQ options, sendmail also includes the following warning headers in the letter to help alert the recipient of possible mail forgery:

X-Authentication-Warning: gonzo.gov: Processed from queue /tmp
X-Authentication-Warning: gonzo.gov: Processed by joe with -C srvr.cf

sendmail also inserts the header Apparently-to: joe because, although you specified a recipient on the command line, none was listed in the body of the letter. In this case, the letter's body was taken from the empty file /dev/null, so no To: header was available. If you do your testing as the superuser, you can skip the -oQ argument and sendmail won't insert the warning headers. You can avoid the Apparently-to: header by creating a file like

To: recipient

testing

and using it as input instead of /dev/null.

The recipient should be you, so you can inspect the headers of the letter for correctness. In particular, return address lines must include an FQDN (Fully Qualified Domain Name) for SMTP mail. That is, a header such as From: joe@gonzo is incorrect because it doesn't include the domain part of the name, but a header such as From: joe@gonzo.gov is fine.

You should repeat this testing for the same variety of addresses you used in the first tests. You might have to create special aliases that point to you for some of the testing.

The amount of testing you do depends on the complexity of your site and the amount of experience you have, but a beginning system administrator should test very thoroughly, even for apparently simple installations.

When you are absolutely sure that the sendmail.cf file is correct, you can copy it into place in the /etc directory:

[root@gonzo cf]# cp /etc/sendmail.cf /etc/sendmail.cf.bak
[root@gonzo cf]# cp gonzo.cf /etc/sendmail.cf

The first copy backs up your current sendmail configuration in case you need to get it back for any reason. Then you can stop and start sendmail or find the process ID and send it a HUP signal. This causes sendmail to reread its configuration file:

 [root@gonzo cf]# /etc/rc.d/init.d/sendmail restart

Common sendmail Configuration Mistakes

There are three main common configuration errors when you are setting up a sendmail-based mail server.

The first is not having an alias for the postmaster user. All bounced messages get sent to this alias, which should point to a user who regularly reads his mail. When you get bounced messages for your site, you should READ them! Most of the time it helps you diagnose a problem before the users notice it and start complaining. It is also a widely known alias that Internet users commonly mail to if they need to contact an email administrator for a particular domain name.

The second is having an incorrectly configured sendmail.cw file. This file should list all the domain names for which the server is responsible for receiving mail.

The third is due to incorrectly configured DNS entries. Most of the time sites have incorrect secondary MX records, which is of no use if your main email server goes down for a period of time. Usually your ISP will be happy to act as a secondary MX for your site.

Share ThisShare This

Informit Network