Intro
News
Humor
Sysadmin
Programming
Books
Screenshots
Firefox Extensions
Kitty
Links!
Employment

Although sendmail is one of the most powerful and full-featured mail transport agents out there, it's also one of the most complex and byzantine. There's a lot that can be done to make the task of administering a sendmail installation simpler, though. Some of the ways I make the task easier are covered here.

  • sendmail_build.sh is a simple shell script to build and configure sendmail according to how I like it configured. Some manual tweaking will be required after it's built.
  • sendmail_conf.sh -- Lets me reconfigure a sendmail installation that's already existant to suit my needs.

Verbose configuration guide

Since I started administering sendmail back in the 8.6 days, I'm still used to the old sendmail syntax. As such, my sendmail.mc file reflects the old layout more than the newer. If you prefer the new syntax for file locations and names, just rip out the corresponding lines from the sendmail.mc. Those will be marked as such.


Here follows my sendmail.mc, cleaned up a bit:


VERSIONID(`$Id: generic-linux.mc,v 8.1 1999/09/24 22:48:05 gshapiro Exp $')
OSTYPE(linux)dnl

DOMAIN(generic)dnl

MASQUERADE_AS(`net-ronin.org')dnl

FEATURE(`no_default_msa')dnl
FEATURE(`access_db')dnl
FEATURE(`access_db', `hash -o /etc/mail/access')dnl
FEATURE(`allmasquerade')dnl
FEATURE(`masquerade_envelope')dnl
FEATURE(`smrsh')dnl
FEATURE(`blacklist_recipients')dnl
FEATURE(`genericstable')dnl
FEATURE(`local_procmail',`/usr/bin/procmail')dnl
FEATURE(`masquerade_envelope')dnl
FEATURE(`nouucp',`reject')dnl
FEATURE(`use_ct_file')dnl
FEATURE(`use_cw_file')dnl
define(`ALIAS_FILE',`/etc/mail/aliases')dnl
define(`confCHECKPOINT_INTERVAL',`10')dnl
define(`confCW_FILE',`/etc/mail/sendmail.cw')dnl # old-style
define(`confCT_FILE',`/etc/mail/sendmail.ct')dnl # old-style
define(`confDOMAIN_NAME',`ramune.net-ronin.org')dnl
define(`confHELP_FILE',`/etc/mail/sendmail.hf')dnl # old-style
define(`confSTATUS_FILE',`/etc/mail/sendmail.st')dnl # old-style
define(`confMCI_CACHE_SIZE',`10')dnl
define(`confCONNECTION_RATE_THROTTLE',`5')dnl
define(`confERROR_MODE',`m')dnl
define(`confMAX_DAEMON_CHILDREN',`5')dnl
define(`confMAX_MESSAGES_SIZE',`1000000')dnl
define(`confMIN_FREE_BLOCKS',`3000')dnl
define(`confPRIVACY_FLAGS',`goaway,restrictmailq,restrictqrun,noetrn,noreceipts')dnl
define(`confQUEUE_LA',`10')dnl
define(`confQUEUE_SORT_ORDER',`Time')dnl
define(`confREFUSE_LA',`15')dnl
define(`confSAVE_FROM_LINE')dnl
define(`confSMTP_LOGIN_MSG',`Ancrix Mail Server, v1.3')dnl
define(`confSUPER_SAFE',`true')dnl
define(`confTIME_ZONE',`PST8PDT')dnl

MAILER(local)dnl
MAILER(smtp)dnl
MAILER(procmail)dnl

Now, let's go through this one piece at a time.


VERSIONID(`$Id: generic-linux.mc,v 8.1 1999/09/24 22:48:05 gshapiro Exp $')
OSTYPE(linux)dnl

DOMAIN(generic)dnl

The above three lines are from the standard sendmail distribution. For most people, there will be no need to modify the VERSIONID. You do NOT want to modify the DOMAIN directive, unless you happen to be on an ancient VAX running BSD at UC Berkeley (those are the only DOMAIN data files defined in the sendmail source distribution). The OSTYPE should match the operating system you are using, assuming a configuration file for it exists in the sendmail package. You can check by looking in $srcdir/cf/ostype/.

MASQUERADE_AS(`net-ronin.org')dnl

The MASQUERADE_AS directive tells sendmail to make everything it sends look like it came from the net-ronin.org domain. So if you have your internal systems configured to be part of the zorkmid.edu domain, you don't want mail sent from a host called grue to appear as if from user@grue.zorkmid.edu out on the 'net. Unless, of course, you actually have that host's A and MX record registered, visible externally, and accepting mail for it.

FEATURE(`no_default_msa')dnl

The FEATURE line tells sendmail to enable a certain capability that's not normally enabled by default, or in this case, to disable a capability that's normally enabled by default. Sendmail now has a local mail delivery port opened, listening to all interfaces. Since I'm on a dial-up account on a single-user system, I'm perfectly content with having sendmail listening only on the loopback interface (i.e. mail to/from localhost only), have fetchmail grab remote mail, and have sendmail invoked explicitly when a mail is being sent out. So I disabled this port.

FEATURE(`access_db')dnl
FEATURE(`access_db', `hash -o /etc/mail/access')dnl

Some spammers insist on sending you stuff over and over and over and... well, you get the idea. The access database lets you blacklist domains and usernames, along with a reason/rejection code if you want. This is a handy feature to have around, just in case. The second FEATURE line above tells sendmail that the access database is in /etc/mail/access, and should be written out in Berkeley DB hash format. sendmail will write it out in /etc/mail/access.db.

FEATURE(`allmasquerade')dnl
FEATURE(`masquerade_envelope')dnl

The above two features tell sendmail to masquerade everything, so it looks like it was sent from part of the domain being masqueraded as. The masquerade of the envelope is a bit weird for people not used to thinking about e-mail having an envelope, so let me explain (briefly!).

When a mail is being sent, the To:, From:, and other fields are put into the mail itself. These fields controls what the client sees when he opens the mail in a mail reader. The envelope, however, is what sendmail, the mail readers, and other software that handle mail use when sending mail. The envelope may say, "This mail is from user foo@example.org, and this mail should be sent to user baz@invalid.com." The content of the mail (what the user reads) may say, instead, "From: john@test.net, To: bob@localhost". So the envelope is what really controls the mail delivery.

If that's still confusing, think of regular postal mail. On the envelope, you put your return address on it (From ) and your intended delivery recipient (To ). The letter inside the envelope has a standard letterhead that contains the sender address (From: ) and a salutation line that mentions who the letter is for (To: ).

FEATURE(`smrsh')dnl

The sendmail restricted shell, smrsh, is a shell that can be used by sendmail to run external programs that you direct it to. I won't get into this too much, as I don't really use this feature, but let's just say it's a good idea if you're going to have sendmail automatically process mail other than through the normal mail.local/procmail binaries.

FEATURE(`blacklist_recipients')dnl
FEATURE(`genericstable')dnl

blacklist_recipients allows you to reject mail based on the username, hostname, or full address of the e-mail's target. So if want all mail sent to user daemon@localhost to be denied, you can put it in /etc/mail/access.


The format of the file is:

daemon@			REJECT
router.example.com	ERROR:550 No one can send mail to that system.
evil@example.com	ERROR:550 User mailbox has been disabled.

Then you can rebuild the access database via:

sendmail -bi

OR

newaliases

The genericstable feature lets you rewrite addresses that are missing the domain and those listed in the G class to be modified. This feature can be used to do a LOT of weird things, so I'll just explain how it's being used on my system:

Here's my /etc/mail/genericstable:

barbeque@kittens.example.net enzhar@arg-ebava.bet
barbeque@localhost.example.net enzhar@arg-ebava.bet
barbeque@localhost enzhar@arg-ebava.bet
barbeque@kittens enzhar@arg-ebava.bet
barbeque enzhar@arg-ebava.bet

As you might have guessed, I'm using it to have sendmail rewrite mail from my local account to appear to be from my ISP account. You can do much more interesting things with this feature. For more tricks you can do with this, read the file $srcdir/cf/README.

FEATURE(`local_procmail',`/usr/bin/procmail')dnl

This directive tells sendmail to use procmail to deliver mail to the system (i.e. write it into your inbox) instead of /bin/mail.local or /bin/mail.

FEATURE(`nouucp',`reject')dnl

I don't use UUCP on my dialup system, so might as well rip it out.

FEATURE(`use_ct_file')dnl

The ct file is a list of trusted users. Trusted users can run sendmail manually from the command-line (or from programs) and tell it to change what user the mail seems to have originated from without inserting a warning about it in the mail.


FEATURE(`use_cw_file')dnl

The cw file tells sendmail what other names should be considered equivalent to the localhost. That is, if mail addressed to localhost, foobar, mail, linuxbox, and example.org should all be considered to be "this system", you'd add them to the cw file.


define(`ALIAS_FILE',`/etc/mail/aliases')dnl

The alias file lets you map the username in the To: field to other usernames on your system, to programs, etc. Note: You really don't want to alias an address to a program unless you KNOW that feature can't be exploited. Better to just deliver the mail to a mailbox, and have a script check it out of cron periodically. If in doubt, don't deliver to programs.

define(`confCHECKPOINT_INTERVAL',`10')dnl

The checkpoint is a very useful feature. Enable it! When sendmail has to abort for some reason or another while sending mail to a laaaaarge number of recipients, it will start sending the mail over from scratch from the first recipient. You don't want that. The checkpoint interval tells sendmail to keep track of which people it has sent mail to so far every X number of addresses. In the above example, it's saving the state every 10 addresses, so at worst, you'll only re-send the mail to about 9 people. Of course, I haven't had a need to send mail to that many people at once in quite a while, so I can probably rip it out of my sendmail.mc now. :-)

define(`confCW_FILE',`/etc/mail/sendmail.cw')dnl
define(`confCT_FILE',`/etc/mail/sendmail.ct')dnl
define(`confSTATUS_FILE',`/etc/mail/sendmail.st')dnl
define(`confHELP_FILE',`/etc/mail/sendmail.hf')dnl

These directives tell sendmail what the path and name of the various files that it can use are. I'm used to the old sendmail configuration, so I changed it from the default to these. The newer versions of sendmail have readable names (for those who are just starting sendmail). i.e. the sendmail.cw is called relay-domains. I got used to the old syntax, though. You probably don't want these in there unless you like old-style sendmail configuration, too.

define(`confDOMAIN_NAME',`ramune.net-ronin.org')dnl

This tells sendmail what your domain name is.

define(`confPRIVACY_FLAGS',`goaway,restrictmailq,restrictqrun,noetrn,noreceipts')dnl

The PRIVACY_FLAGS directive tells sendmail what security features to enable. The above configuration disables the following:
  • The ETRN ESMTP command.
  • THE VRFY ESMTP command.
  • The EXPN ESMTP command.
  • The ability for non-root users to run /usr/bin/mailq
  • restrictqrun disallows the use of the -q command-line option for non-trusted users.
  • DSN, Delivery Status Notification.

define(`confSMTP_LOGIN_MSG',`Ancrix Mail Server, v1.3')dnl

The above tells sendmail what the version string it should send clients are. Changing this is a good idea, because there's a lot of DUMB exploits that just scan it for a string that says "sendmail". Of course, even stupider (and smarter) exploits that ignore the version string can't be shunted away by this simple trick.

define(`confSUPER_SAFE',`true')dnl

Turns on lots of paranoid stuff in sendmail. Generally a good idea. Don't disable this unless you know what you're doing.

define(`confERROR_MODE',`m')dnl

You can tell sendmail how you want to be notified of errors. The default method is to print it to the console, which isn't too helpful when you're trying to debug stuff on a remote system, or if you're in X. You can also have it log to a file, or mail it out. I told it to mail it, since it'll drop it into the root mailbox. Never alias off root until you have your sendmail configuration set perfectly. Even then, it's generally not a good idea.

define(`confMAX_MESSAGES_SIZE',`1000000')dnl

On dialup, it's rather painful when someone tries to send you a huuuuuuuuge mail that sucks up all your bandwidth. In those cases, you'd probably rather just connect to the POP3 server and delete the mail manually. For this, I put the maximum limit for the mails in sendmail (it's in bytes). You'll probably want to do this too.

define(`confCONNECTION_RATE_THROTTLE',`5')dnl

This limits the number of connections that can be made per-second to 5. Since I'm on dialup, this isn't really a problem.

define(`confMAX_DAEMON_CHILDREN',`5')dnl

The maximum number of child processes sendmail should spawn.

define(`confMIN_FREE_BLOCKS',`3000')dnl

Once the number of free blocks on the filesystem sendmail is delivering to falls below this number, stop accepting mail.

define(`confQUEUE_LA',`10')dnl
define(`confREFUSE_LA',`15')dnl

The QUEUE_LA directive tells sendmail what load average the system should be under before it starts queueing the mails it receives instead of trying to deliver them. The REFUSE_LA tells sendmail to stop accepting mail once the load average reaches this water mark.

define(`confSAVE_FROM_LINE')dnl

Tells sendmail not to nuke the From line.

define(`confTIME_ZONE',`PST8PDT')dnl

Tells sendmail what time zone you're in.

define(`confMCI_CACHE_SIZE',`10')dnl
define(`confQUEUE_SORT_ORDER',`Time')dnl

The confMCI_CACHE_SIZE directive tells sendmail how large you want the connection cache to be. You probably don't need to modify this. confQUEUE_SORT_ORDER controls the method used to sort the mail queue. The options you can use are:

  • Filename
  • Host
  • Modification
  • Priority
  • Random
  • Time
Unless you're sending out or receiving thousands of messages every hour, you probably don't need this.

MAILER(local)dnl
MAILER(smtp)dnl
MAILER(procmail)dnl

The "mailers" defined for the system. A "mailer" tells sendmail it can send mail to another location via these methods. The local mailer delivers mail to mailboxes on the local host. The SMTP mailer sends mail out via the SMTP and ESMTP protocols. The procmail mailer must be defined after the local mailer. It allows you to use procmail as the mail delivery agent for local deliveries.