datixlogo

      Document made with KompoZer

Mail Server Setup


Some years ago I lived in Brookside, NJ, a community of upscale homes trying desperately to retain a rural atmosphere while suburban sprawl spread elsewhere like a blight.   There were even a few fragrant cattle farms left.
One symbol of rural life was mightily protected - the local post office. There was no mail delivery; we pridefully drove to the little rural postoffice to collect our mail each day.   This had social benefits of meeting our neighbors, but it was not efficient.   Almost everyone else prefers to have their mail delivered directly to their homes and, but for the symbolism, so would we.

Computer email is designed and intended to provide automatic and nearly instantaneous delivery  from sender to recipient.  However, Windows users, whose machines seem unable to reliably function 24/7, and who cannot intelligently configure their systems to run mail delivery services, depend on services provided by their ISP.   They seem content to use the primitive method of running frequently to a mail collection service to check if any new mail has arrived, even though there are no discernible benefits, social or otherwise.   As this blight has spread, this primitive system has become the norm.

It needn't be so.   Linux has always been designed to receive email directly and instantly from the sender.   Linux is certainly reliable enough to run 24/7 for years on end.   Having your mail delivered automatically, door to door, as it were, merely requires configuring the mail transport service properly.   Unfortunately, as abusers of internet services proliferate, this task becomes more complex.   Topics discussed below are:

  • Domain name & IP
  • Sendmail configuration
  • Spam and viruses
  • Procmail

Domain name and IP

A prerequisite to receiving mail directly to your machine is a domain name along with a DNS entry that translates that domain name to your machine's IP address.   For mail addressed to dad@datix.us to be deliverable, the DNS system must translate the string  datix.us   to my current numerical IP address.   If I had a static IP, the provider would make that DNS entry once and for all.  But I, and most others, do not.   My cable connection provider assigns an IP dynamically and is free to change it at his whim.   This makes no sense.   It may have when folks used modems and connected for brief periods.   An ISP could service many customers with fewer distinct IPs. But with cable connections that are on continously, a distinct IP is needed for each customer.   It's clear that dynamic IPs are just a marketing ploy to make you pay extra for the convenience of a static IP.

Fortunately, many commercial enterprises offer dynamic domain name services for a fee, or even for free.  Originally, I purchased my very own domain name, datix.us, from godaddy.com, but then became annoyed with their business practices, and switched to namecheap.com.  Namecheap has proven to be reliable and easy to work with.  Linux provides a script, ddclient, that looks up my current IP address once an hour and, if it has changed, automatically notifies namecheap.com and updates the DNS data.  Thus, datix.us will always be translated to my current IP, except for a brief period after it changes.  In practice, my IP almost never changes.

Sendmail configuration

Sendmail is the granddaddy of UNIX/Linux mail transport agents.   Some "progressives" advocate replacing it with postfix, but I prefer sticking with the tried and true.  Because mail is an obvious way to transmit mal-ware into an innocent system, sendmail has been the target of more subversive attacks than almost any other program.   Each and every attack has been thwarted and blocked so that, after decades of improvement, it is safe say that sendmail is bulletproof, or as safe as any software of such complexity can ever be.   Sendmail is a very complex program because it has to operate in a huge variety of situations and provide many options.   The definitive O'Reilly book, Sendmail, by Bryan Costales with Eric Allman, is 2 inches thick and 1021 pages long.   Many people are intimidated by this amount of complexity.   The main configuration file, /etc/mail/sendmail.cf, uses a unique and arcane special language that only the author can love.   However, in all recent versions, a relatively compact sendmail.mc file contains a more readable structure of commands that are processed by the m4 language interpreter to construct the more difficult sendmail.cf file. Fedora provides a standard version that serves as a basis for modification.

Sendmail implements the two-way SMTP protocol.   It communicates with a similar member in another machine to send or receive messages over an internet channel.   In the daemon mode, sendmail listens continuously for packets on port 25 and when a peer machine sends a message, sendmail analyzes the header and disposes of the message in various ways.   Some of the possibilities are to

  • recognize the addressee as a local user and deliver the message to a local mailbox
  • recognize the addressee as an alias and deliver to that user, possibly on a different machine
  • recognize the address as a permitted forwarding domain and relay it to another machine
  • discover that a DNS lookup of the sender fails, so the message is refused
  • determine that no such addressee exists locally, so the message is rejected
  • etc.

A second non-daemon instance of sendmail is also used to send mail.   The program that creates the message pipes it to sendmail, which analyzes the headers and tries to deliver it.

  • if multiple addressees are found, each one is processed
  • if the addressee is local the message is delivered locally
  • if the destination is a nearby machine it is forwarded there
  • if no rule for delivery can be found, the message is forwarded to a "Smart Host" for further processing, else it is rejected
  • the identity of the sender may be altered according to masquerading rules

If sendmail fails to connect to the destination machine, the message is stored in /var/spool/mqueue/, and transmission is queued for a later attempt.   After successive failures over a four day interval, a failure notice is returned to the sender.

sendmail.mc edits

Configuring all this is surprisingly simple.   Here are the changes, in diff format, that I've made to the standard sendmail.mc file provided by Fedora 26:

# diff sendmail.mcSTD sendmail.mc
39c48
< define(`confAUTH_OPTIONS', `A')dnl
---
> dnl define(`confAUTH_OPTIONS', `A')dnl
45,48c54,57
< dnl #
< dnl # which realm to use in SASL database (sasldb2)
< dnl #
< define(`confAUTH_REALM', `mail')dnl
---
> define(`confAUTH_OPTIONS', `A p')dnl
> define(`confMILTER_MACROS_CONNECT', confMILTER_MACROS_CONNECT`, {daemon_port}')dnl
> define(`confMILTER_MACROS_HELO', confMILTER_MACROS_HELO`, {verify},{client_resolve}')dnl
> define(`confMILTER_MACROS_ENVRCPT', confMILTER_MACROS_ENVRCPT`,{client_resolve}')dnl
57a67,69
> TRUST_AUTH_MECH(`EXTERNAL DIGEST-MD5 CRAM-MD5 LOGIN PLAIN')dnl
> define(`confAUTH_MECHANISMS', `EXTERNAL GSSAPI DIGEST-MD5 CRAM-MD5 LOGIN PLAIN')dnl
> FEATURE(`authinfo',`hash /etc/mail/auth/client-info')dnl
67a80,85
> define(`confCACERT_PATH', `/etc/pki/tls/certs')dnl
> define(`confCACERT', `/etc/pki/tls/certs/ca-bundle.crt')dnl
> define(`confSERVER_CERT', `/etc/pki/tls/certs/sendmail.pem')dnl
> define(`confSERVER_KEY', `/etc/pki/tls/certs/sendmail.pem')dnl
> define(`confCLIENT_CERT', `/etc/pki/tls/certs/sendmail.pem')dnl
> define(`confCLIENT_KEY', `/etc/pki/tls/certs/sendmail.pem')dnl
122c140
< DAEMON_OPTIONS(`Port=smtp,Addr=127.0.0.1, Name=MTA')dnl
---
> DAEMON_OPTIONS(`Port=smtp, Name=MTA')dnl
130a149,152
> dnl # SRD googled to find this, instead
> dnl #
> DAEMON_OPTIONS(`Port=587, Name=MSA, M=Ea')dnl
> dnl #
140c162
< dnl DAEMON_OPTIONS(`Port=smtps, Name=TLSMTA, M=s')dnl
---
> DAEMON_OPTIONS(`Port=smtps, Name=TLSMTA, M=s')dnl
155c177
< FEATURE(`accept_unresolvable_domains')dnl
---
> dnl FEATURE(`accept_unresolvable_domains')dnl
166c188
< dnl MASQUERADE_AS(`mydomain.com')dnl
---
> MASQUERADE_AS(`datix.us')dnl
170c192
< dnl FEATURE(masquerade_envelope)dnl
---
> FEATURE(masquerade_envelope)dnl
174c196,197
< dnl FEATURE(masquerade_entire_domain)dnl
---
> FEATURE(masquerade_entire_domain)dnl
> FEATURE(local_no_masquerade)dnl
179c202
< dnl MASQUERADE_DOMAIN(mydomain.lan)dnl
---
> MASQUERADE_DOMAIN(datix.lan)dnl

Other files

There are some other important files in /etc/mail that are referenced in sendmail.mc and used by sendmail.

The  access file lists machines and domains that are allowed to relay through this machine.   All others are disallowed.   This is critically important to prevent this machine from being hijacked by spammers for their nefarious purposes.   All my local machines are listed here and given RELAY permission.

The local-host-names file lists all the names by which this machine is known, allowing local delivery of messages:

Whenever any file in /var/mail/ is modified, run 'make'.   This will convert the text source files to the database files that sendmail actually uses.


Relaying for selected external machines

The lines in sendmail.mc above prepare the server to accept logins from external client machines to relay email.  Those client machines must be configured in a similar way but to use this server, datix.us, as their SMART_HOST.   In addition, the client machine needs this line added to /etc/mail/sendmail.mc:
FEATURE(`authinfo',`hash /etc/mail/auth/client-info')dnl

To provide the necessary authorization data, create /etc/mail/auth/ with permissions
drwx------ 2 root root 4096 May  2 19:48 auth

and in that directory a file,  client-info with lines such as:

        AuthInfo:datix.us  "U:dad"  "I:dad"  "P:<dad's_passwd>"

Then run the command
  makemap hash client-info < client-info
  chmod 600 client-info*

to create the database file needed by sendmail and make it secure.

Email name aliasing

Sometimes it is desirable to use one name internally and a different name externally.  For example, my internal usrname is dad, but I might wish to use dadegraaf as my email name.   Two files in /etc/mail make this conversion easy.
$ cat genericstable
#  Translates local names to external email addresses of outgoing mail
dad@datix.lan    dadegraaf@datix.us

The translation for incoming mail is in
$ cat virtusertable
#  Translates external names to local email addresses on incoming mail
dadegraaf@datix.us    dad

Spam and virus blocking

Three methods are used to minimize intrusion of obnoxious email - greylisting, clamav and spamassassin.   They are installed nowadays with dnf:
dnf install milter-greylist clamav spamassassin

No further configuration is required, except that /etc/clamd.d/milter.conf needs to be edited to comment out the "Example" line.   Greylisting is described by the author, Evan Harris, in a whitepaper, but its operation can easily be summarized.   A mysql database contains data on previous email senders.   If a new message arrives matching existing data, it is accepted.   Otherwise, it is refused without even allowing the message to be received, but the sender's data is retained.  When the sender tries again, in accordance with the SMTP protocol, it is accepted.   Thus, new senders suffer a slight delay for their first email.  Successful spam blocking relies on the fact that spammers usually lack the patience, resources or observance of the protocol to try again.   The vast bulk of spam is rejected without ever entering the system, reducing the burden on spamassassin to analyze the content.

Clamav uses a database containing descriptive data of known viruses.   If a message appears to match, it is not delivered.   There are mighty few known Linux viruses, so this is mainly of benefit to any Windows machine in the LAN.

Any message that makes it through is then examined by spamassassin.   It uses a sophisticated statistical spam scoring system.   If the rating is above a threshold (5.0) it is so labelled.   When I first implemented spam testing in Feb 2005 the number of spams detected by spamassassin went from 120/day to 6/day.   Recent logs  show about 3.9/day.   This combo is very effective.

Finally, procmail tries to deliver the message, using global rules in /etc/procmailrc and my personal rules in ~/.procmailrc.   The global rules divert the message to /usr/tmp/spamtrap if it has been labeled as spam.   My personal rules divert mailling list messages to their own mailboxes and deliver the rest to me.