Networking

Build Your Skills: Features, testing, and performance tuning of Sendmail

Read about a proven program that can do some pretty sophisticated mail processing.


In the last Daily Drill Down, “Understanding sendmail from the ground up,” I covered where to get sendmail, as well as how to build it from source and set up a basic sendmail.cf using the sendmail .mc files and options. This time, we're going to cover some additional .mc options and the effect they have on sendmail.cf. We'll also cover some command-line switches and ways you can use sendmail itself to test any address rewriting you do using aliases or masquerading. Finally, I’ll offer a little information on performance tuning and how to analyze the sendmail statistics and log files.

Enabling additional features
Let’s look at some more of the features that can be enabled in the .mc file, which is used to generate sendmail.cf. Just as a refresher, we define our configuration in the .mc file and then use the m4 processor to generate the .cf file:
/usr/bin/m4 ../m4/cf.m4 mysite.mc > mysite.cf

Sendmail now ships with relaying disabled. In the early days of the Internet, these things weren't such an issue, but with the overwhelming amount of spam we all get, it's been necessary for responsible system administrators to tighten up the control on whose mail passes through their systems. If you want to reenable relaying, add the following feature to your .mc file:
FEATURE(`promiscuous_relay')

If you want to only open up relaying to your own domain, then use:
FEATURE(`relay_entire_domain')

The other side of the coin is how to set up a server to appear to be another domain. This is useful if you are relaying mail from an unqualified domain, such as a small business or home server, but want to queue up the mail and batch it through to your ISP. This involves masquerading and, like relaying, there are several layers of control that can be enabled. The simplest level of masquerading is:
MASQUERADE_AS(host.domain)

So if your machine is mymailer.fakedomain.org, and you want outgoing mail to look like it came from your valid e-mail account at myisp.com, you would use myisp.com as the host.domain entry. In the sendmail.cf file, it generates this line, plus a number of addressing rulesets further down the file (rulesets 93 and 94).

Some sites will still bounce this mail, so you may need to masquerade the envelope:
FEATURE(`masquerade_envelope')

If you want to expose certain users, you can enter them in:
EXPOSED_USER(usernames)

You can also set up a virtual hosting setup, where your mailserver can act as a virtual host for a number of domains:
FEATURE(`virtusertable')

In this case, you map the incoming mail address to the local system recipient:
info@somedomain.com        larry

To map the outgoing mail in the same way, use the genericstable feature:
FEATURE(`genericstable')

and set up /etc/mail/genericstable like virtusertable, but with the entries reversed:
larry       info@somedomain.com

If you have a number of machines and want to relay all mail through one before going to the ISP, then enable:
define(`LOCAL_RELAY', `mailer:hostname')

All mail with unqualified addresses (no @host) will get relayed to the local relay machine. In sendmail.cf, the resultant line looks like this.

A related feature is:
define(`SMART_HOST', `mailer:hostname')

mailer defaults to relay, but smtp is also common. This generates the following line in sendmail.cf:
# "Smart" relay host (may be null)
DSsmtp.myisp.com


An interesting feature allows relaying based on the MX records of the host portion of an incoming recipient address. If this is enabled, another domain can add you as an MX record in its DNS setup and relay its mail through your system, with no prior arrangement with you. Consequently, use caution in enabling this feature.
FEATURE(`relay_based_on_MX')

Similarly, the feature:
FEATURE(`relay_local_from')

allows spammers to relay through your system by simply specifying a return path, which is a local domain. Again, caution is advised. You can control this further by using:
FEATURE(`relay_mail_from')

This allows relaying if the mail sender is listed as RELAY in the access map.

If you've ever set up your own Linux box with a made-up domain and then tried to send Internet mail only to find it bounced right back at you, you probably encountered a system that had not enabled the following feature:
FEATURE(`accept_unresolvable_domains')

Your fancy myscreamingmachine.myhouse.org domain name is not resolvable out on the greater Internet's DNS, so whatever system received the message refused to accept it. By default, sendmail comes with this feature disabled.

If you want to fine-tune control of which domains (and even users) you will accept mail from, then use:
FEATURE(`access_db', `hash /etc/mail/access')

You can specify a second parameter with the name of the access file; don't forget that you'll need to use makemap again to create a database file from the text file. You can specify domains or individual users on the left-hand side of the file, with REJECT, OK, RELAY, DISCARD, or various ERROR messages on the right-hand side:
spammer@yahoo.com          REJECT
cyberspammer.com           REJECT
mybuddy@cyberspammer.com   OK


You can also set up a "blacklist" for your own systems and users, using:
FEATURE(`blacklist_recipients')

Again, this is a tabular list and can have users and domains, which forces clients to check their incoming mail on the POP server before they can send outgoing mail through the Simple Mail Transfer Protocol (SMTP) server.

Since many mail clients act in just this manner anyway, nothing special is required of the user, and only users with authorized mail accounts can relay mail through the server.

That covers most of the common controls on what mail will pass through your server. There are others, and the sendmail site covers them in detail.

Running in test mode
Another interesting way you can run sendmail is in test mode, which allows you to check your aliases and address rewriting rules. You can do this by running sendmail with the -bv or -bt switches.

Say you have the following alias file, with two administrators that receive root's mail, as well as an aliased list of users called “management.”
root:               stew, Dianne
management:         stew, fred, Justin

[stew@omnibook mail]$ /usr/sbin/sendmail -bv root
dianne... User unknown
stew... deliverable: mailer local, user stew


So we can see that the “dianne” user is no longer a good account on the machine.
[stew@omnibook mail]$ /usr/sbin/sendmail -bv management
justin... User unknown
fred... User unknown
stew... deliverable: mailer local, user stew


Likewise, “Fred” and “Justin” are no longer valid accounts.

As you can see, this is a very easy way to test your aliases file. If you have a system with a lot of user accounts and a lot of accounts being added and removed, you might want to set up a cron job to walk through the aliases file and send you an e-mail of any invalid addresses.

You can also run sendmail with the -bt switch to test your address rulesets. Once it’s run, you find yourself at a “>” prompt, where you can enter a ruleset number or name and an address, and you will be able to see how the address flows through the ruleset and gets processed.
[stew@omnibook mail]$ /usr/sbin/sendmail –bt
ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)
Enter <ruleset> <address>
> 0 stew
parse              input: stew
Parse0            input: stew
Parse0           returns: stew
ParseLocal         input: stew
ParseLocal       returns: stew
Parse1             input: stew
Parse1           returns: $# local $: stew
parse            returns: $# local $: stew


If we're using a masquerading or genericstable setup, this can be used to insure the "from" addresses are getting rewritten as we expect them to.
> 31 stew
HdrFromSMTP        input: stew
PseudoToReal       input: stew
PseudoToReal     returns: stew
MasqSMTP           input: stew
MasqSMTP         returns: stew < @ *LOCAL* >
MasqHdr            input: stew < @ *LOCAL* >
MasqHdr          returns: stew < @ myisp . com . >
HdrFromSMTP      returns: stew < @ myisp . com . >


Ruleset 31
Ruleset 31 is for header sender rewriting.

It's kind of neat to watch how an address works its way through the various rulesets and gets modified. Here's one for our Yahoo spammer that we set up in the access_db.

These examples give you an overview of some of the things you can do by enabling different sendmail options and features, as well as a more efficient way to test them than just throwing mail out there and hoping it arrives. If you’re using a lot of the database table controls, it probably wouldn't hurt to set up some scripts to run new entries through the test mode after they're added. In fact, you could automate the whole process of adding a new entry to one of the database tables, run makemap, restart sendmail, and process the new entry through the test mode.

Sendmail performance tuning
Now that we know a bit about the level of control we can exert on mail traveling in and out of our systems, let’s take a look at what we can do to get maximum efficiency out of running sendmail. There are a number of options we can set to control how mail is processed, as well as how well sendmail will coexist with other software running on your system.
QueueSortOrder=host

This feature makes the best use of the Connection Caching feature if your system transfers large quantities of mail to a number of users at the same host. The outgoing mail queue is sorted by hostname and, by caching the connection, a number of messages to one host can all go through during one connection, rather than adding the overhead of opening and closing a number of SMTP connections.

If you are handling a very large volume of mail, you may need to take steps to increase the efficiency of the mqueue directory by using a separate disk, RAID, or a hashed filesystem such as XFS. You may also need to run additional mqueue processors with a mix of QueueSortOrder of both "host" and "time" in order to clear out messages quickly, as well as insure that the oldest messages don't get bounced.

Sendmail makes heavy use of DNS, and if you are going to be processing a heavy mail load, try to avoid running both sendmail and bind on the same machine, where they'll end up competing for resources.

There are other options that will control how well sendmail will coexist with other programs on the system:
  • ·        ConnectionCacheSize holds open "n" number of connections for subsequent mail to the same host.
  • ·        ConnectionCacheTimeout defines the timeout for the connection.
  • ·        ConnectionRateThrottle slows incoming connections so as not to overload the machine.
  • ·        HoldExpensive can define certain mailers as "expensive" and run those queues at low load periods.
  • ·        MaxDaemonChildren limits the number of forked child processes.
  • ·        MinQueueAge won't process queues that are too young.
  • ·        QueueFactor works in conjunction with the QueueLA option to adjust whether to send mail or queue it, based on system load.
  • ·        QueueLA is the load average where sendmail starts queueing rather than delivering.
  • ·        RefuseLA is the load average where sendmail starts refusing incoming mail.

The sendmail site gives all the details on how to set these options and what the defaults are.

Sendmail log files
Our final topic for this Daily Drill Down is looking at statistics on what your mailserver has been up to. The sendmail distribution comes with mailstats, which will give a basic rundown of the messages transferred through the system.

This is telling us that 15 messages, for a total of 28 KB, were transferred from the local mailer, while 664 messages at 2589 KB were transferred from SMTP, with one outgoing message through SMTP. Again, you could automate this via a cron job to report the stats daily and reset the log file:
#!/bin/sh
mailstats -f /etc/mail/statistics
cat /dev/null > /etc/mail/statistics


If you really want to get into the gory details of what's going on, /var/log/mailog has most of the transaction details of both sendmail and the local mail agent.

This is a bit much to digest, but of course, there are a number of log analyzers that will help with this too. One such tool is mreport (see sidebar).

There are a number of switches that allow you to see only "from" or "to," or apply filters and sorting. Again, you could run this as a cron job and flush the log file after processing, or possibly move it to a backup, so it could be reviewed later should the report reveal issues.

Conclusion
I hope this Daily Drill Down has given you a bit more insight into the workings of sendmail, as well as raise your comfort level in dealing with sendmail.cf. As we've shown, the complicated .cf file is generated from some fairly straightforward .mc options. We’ve also seen that by using the testing mode, it's fairly easy to see if your aliases and rulesets are doing the job you intended them to. Hidden in all that gibberish is a proven program that can really do some pretty sophisticated mail processing.

Editor's Picks

Free Newsletters, In your Inbox