Providing E-mail Services for a Small Office
The company I work for is what could euphemistically be called thrifty. We've got equipment dated from the 1930s, and I worked there three months before I found out we even had an internet account. (Pretty bad for the system administrator, huh?) This was my first true IS job, and I was willing to deal with the situation to get the experience. Come to find out, the account was being hoarded in the engineering department by the owner's son and his buddies.
As time went on, our customers began requiring us to be more in step with the times, accessing information on the Web, sending and receiving e-mail, etc. I saw a number of other ways that adding a Linux box to the network could help out the company and pay for itself in no time. So I wrote a proposal and got permission to procure a box to act as a file server, fax server, internal web server, e-mail server and Internet gateway. Aside from the guys in engineering, the rest of the plant had not even used e-mail, and engineering had only used it once or twice. They thought the Web was the only thing to do on the Internet. We won't talk about what sites they were visiting.
The focus of this article is on the e-mail portion. I intend to cover how to use sendmail, fetchmail and procmail to allow a small company to effectively “hide” behind a single e-mail address. Now, before you run out and do this, you might want to consider how your ISP may feel about it. In our case, the volume of e-mail is small, maybe 20 messages a day. Compared to my personal account, which gets 100-400 a day, plus my business account, which gets maybe 20-30, this is peanuts, and I don't think our ISP has much to complain about. Your mileage may vary.
Did you ever notice how return addresses look when reading e-mail? Most times, if the person has their full name set up in their e-mail client configuration or if the administrator has it in /etc/passwd, you will see something like:
Firstname Lastname <email@example.com>
I was convinced that I could use this, somehow, to rewrite the outgoing return address in such a way that, when the mail was answered, I could pass it through a filter and on to the appropriate person, while only consuming one e-mail address from our ISP. I ending up buying O'Reilly's sendmail book and doing a couple weeks of experimenting, but I've now got a solution that has been in place for about two and a half years and works pretty well. At an additional $5 per e-mail address per month from our ISP, and about 15 users, I think it was worth the trouble.
Here's the plan. The names are, of course, fictitious.
firstname.lastname@example.org—my company's e-mail address from our ISP.
smtp.someisp.com—our ISP's SMTP server (outgoing mail from us).
pop3.someisp.com—our ISP's POP3 server (incoming mail to us).
linuxserver.thriftycompany.com—our file server (thriftycompany.com is strictly internal, not a registered domain).
mrpserver.thriftycompany.com—a Sun box, hosting our MRP system. This is not a necessary part of the plan, but many of my users spend all their time on an xterm to this box, so I installed Pine on the Sun box for them. (Pine, in the GNU tradition, stands for Pine Is Not Elm—another text-based e-mail program. Pine is actually an extremely efficient mail client, and my program of choice. It would take me days to wade through my e-mail with a GUI.)
email@example.com—bogus default e-mail address on the Linux box. All the incoming mail goes through this address, and procmail passes it on to the users.
Through some /etc/sendmail.cf magic, and a procmail filter on the incoming side, I can let several users use the same e-mail account yet, for the most part, keep their mail private.
Outgoing scenario: 1) User writes e-mail, either in Pine on the Sun, or Outlook or Netscape's mail client. I only set up GUI accounts for folks who need to deal with attachments. 2) If mail is written on the PC, it is configured to pass the mail up to the Sun box and retrieve mail from the same location. 3) If it's an internal address, the Sun box delivers it. 4) If it's external, it is passed to the Linux box. 5) Outgoing mail on the Linux box is queued and sent out in batches twice an hour, after incoming mail is pulled in. 6) At the proper time, /usr/sbin/sendmail -q -v is run and, through the use of /etc/genericstable.db and some masquerading rules in /etc/sendmail.cf, the user's return address is rewritten as Firstname Lastname <firstname.lastname@example.org>
Incoming scenario: 1) Server makes connection to ISP at time defined in cron. Or if already connected, leave the connection alone. This is handled by pppd and diald, but that's another article. 2) Incoming mail is retrieved using fetchmail and passed to the default account, email@example.com. 3) Procmail filter in thriftycompany's account looks for proper names in the incoming addresses and passes the mail on to the users. Mail that does not fit a filter rule falls in the default mailbox, and as a precaution, a folder for each user is set up in this account's mail/ directory. 4) All local mail, except root and thriftycompany, gets forwarded to the Sun box. 5) User either receives mail in real time in Pine on the Sun box, or interactively retrieves it from the Sun box using GUI client. 6) All this sounds complicated, but it's really not. Remember, the Sun box is just a convenience for my situation and not necessary to the process. You could merely have your users grab their mail from the Linux box.
Now for the files. Most, if not all, of what you need should be in most Linux distributions already or somewhere on your CDs. Just in case you need assistance, you will find URLs in our Resources section.
Let's get the Sun/Linux mail passing out of the way first, so if you don't need the second server, you can ignore it and move on.
The Sun box's /etc/mail/sendmail.cf is standard. When I set this up, I was still new to Solaris and hesitant to fool too much with a system running our whole plant, so I did this to pass mail out /etc/mail/sendmail.cf entry:
22.214.171.124 linuxserver mailhostBefore I made the change, /etc/hosts had the mailhost entry after the Sun's IP address:
126.96.36.199 mrpserver mailhostThis seemed to do the trick to get outgoing mail over to the Linux box.
On the Linux box, we want all local mail to go to the Sun box, where the users' mail folders reside. None of my users, aside from me, directly log in to the Linux box. They use files shared through Samba. Telnet and FTP access is closed off:
The exceptions to this are root and the thriftycompany user, whom I'd like to stay on this box:
CL root thriftycompanyThat about covers the interaction between the two local UNIX boxes. Local mail stays on the Sun, internet mail gets passed to Linux and then queued for the next connection. Incoming internet mail will get re-addressed to local users and then relayed to the Sun box. The root and thriftycompany accounts on the Linux box stay put, and I check those as part of my daily routine.
Some of this setup was taken from various HOWTOs over the years; other parts I gleaned from scouring Usenet and the O'Reilly sendmail book.
sendmail startup: for a demand dial scenario, we don't want sendmail initiating the connection each time there is mail in the queue, so you need to edit your sendmail startup line to hold off on “expensive” mail:
old entry: /usr/sbin/sendmail -bd -q15m new entry: /usr/sbin/sendmail -bd -os
On a Red Hat-based system, this would be set up in /etc/sysconfig/sendmail and/or /etc/rc.d/init.d/sendmail.
You'll be defining which mail is expensive within the /etc/sendmail.cf file in Listing 1, as well as telling sendmail to hold this type of mail.
Notice the “e” in the “F=” portion for smtp, esmtp and smtp8. This is the “expensive” flag, and we leave it off the local relay. Also the Mlocal and Mprog should not have this flag so that local system mail gets delivered immediately.
A cron job connects to the Internet twice an hour, and as part of that job, we will send out all the queued mail once the internet connection is in place:
/usr/sbin/sendmail -q -v
Now to get the outgoing mail delivered and not rejected by domains on the Internet. Since we do not have a valid domain name, we need to do some work on the return address. We need to masquerade the return address, as well as the envelope, and to get any replies back to the original sender, we need to rewrite the “From:” address.
If you are building up your sendmail.cf from m4 sources, then your local .mc file needs to contain the following:
MASQUERADE_AS(someisp.com) FEATURE(masquerade_envelope) FEATURE(limited_masquerade) FEATURE(genericstable)
We are using limited masquerading so only hosts defined in CM get masquerade. If you are just editing /etc/sendmail.cf, then the following lines need to be modified as shown:
# who I masquerade as (null for no masquerading) (see also $=M) DMsomeisp.comYou will probably also want to relay the mail through your ISP so that any downstream mail servers see the mail as coming from a valid domain:
# "Smart" relay host (may be null) DSsmtp:smtp.someisp.comDefine the domain names that should be converted to the masqueraded address:
CG mrpserver.thriftycompany.com CM mrpserver.thriftycompany.com(If you've got just the one box, this would be linuxserver.thriftycompany.com.)
Now, the sendmail.cf lines to masquerade the contents and the envelope get a bit messy. You would probably be better off building a sendmail.cf from the m4 sources as shown in Listing 2.
The final piece of the outgoing puzzle is to get the user's return address rewritten. If I were to compose a message on the Sun box, Pine would put together a return address that looks something like this:
Stew Benedict <firstname.lastname@example.org>
Looks good enough, except that it is not a real address out on the Internet, and I would never get a reply to my message. Plus, most mail systems would reject it coming in as a nonexistent domain address.
What I want it to look like is this:
Stew Benedict <email@example.com>
This is where sendmail's “genericstable” feature will finish up the job. Again, if you are building up your sendmail.cf from m4 sources, the following line will do the trick:
FEATURE(genericstable)In the sendmail.cf file, if you are hand editing it:
# Generics table (mapping outgoing addresses) Kgenerics hash -o /etc/genericstable(The -o means “optional”, so sendmail will not halt on startup for lack of the file.) This addition to your local .mc file generates the block shown in Listing 3 in sendmail.cf.
The genericstable.db file is built up from a text file of the following format:
stew firstname.lastname@example.org joe email@example.com
This file is then fed to the makemap program to create the db file:
makemap hash genericstable.db < genericstableThat does it for outgoing mail. Once you have finished creating/modifying sendmail.cf and creating the genericstable.db file, you will need to restart sendmail. On a Red Hat-based system, this is done with:
For incoming mail we use fetchmail to fetch the mail from the ISP. My cron job makes the internet connection and then runs a line like this:
su -c "/usr/bin/fetchmail -a -f /home/thiftycompany" thriftycompany's .fetchmailrc: poll pop3.someisp.com proto pop3 user thriftycompany
Procmail is defined as the local MDA (mail delivery agent) in the sendmail.cf file:
Mlocal, P=/usr/bin/procmail, F=lsDFMAw5:/|@qShP, T=DNS/RFC822/X-Unix, A=procmail -a $h -d $uAll the incoming mail goes to the thriftycompany account, where there is a .procmailrc file set up to parse the incoming “To:” lines and forward to the appropriate users, as seen in Listing 4.
You can also use this procmail filter to filter out ILOVEYOU-type viruses, limit or quarantine attachments and other useful things. Check out the procmail docs for more info on this. Each user's mail is held in a folder under thriftycompany, in the event of accidental erasures, etc. I periodically purge these folders by hand.
My boss has not quite bought into the usefulness of the Internet and requests full tracking of its use. Part of my tracking includes logging of all the incoming and outgoing mail messages—quantity and size—per user. This is done through a shell script run by cron every morning, as shown in Listing 5. The output from this job looks like Listing 6.
That about does it. The tricky part is getting outside folks to address the incoming mail properly. For most mail clients, this just requires making a First Name, Last Name and e-mail address entry in the address book, with the person's proper name and our ISP e-mail address. For those people who have regular correspondents who just can't seem to get it right, I add a procmail rule with the “From:” address to make sure the mail gets to its proper destination. The other suggestion I give users is to send an e-mail to the other party and let them add the return address from that to their address book.
There is a certain amount of maintenance to this system on my part, but it's minimal. In writing this article, I've considered ways to automate these portions too; but for now, it's not really much of a burden.
I check thriftycompany's mail daily to check for messages that fell through the procmail filter. Not a big thing, I could forward this mail to myself, and then I'd see it sooner, or I could set up KBiff (KDE mail notification utility) to watch this mailbox.
Also, I like to purge the individual mail folders under thriftycompany's e-mail account. Again, not a big thing. I'm not hurting for space on this server and our volume is small. There's probably a Perl script out there that I could use to prune messages “n” number of days old.
Currently, when I add a new user, I have to add a new entry to the genericstable file, run makemap, restart sendmail and add an entry to the procmail filter for thriftycompany. I've considered making a shell script to accomplish these steps too, but currently I add a user maybe four times a year.
I hope this article has given you some insight into setting up an e-mail solution for a small company, one not quite ready to make the leap into a full DSL or T1 connection with a domain name. If you need to use the Internet and e-mail to communicate with your customers and vendors, this should give you what you need to get the job done.
Stew Benedict is a Systems Administrator for an automotive manufacturer in Cleveland, Ohio. He also is a freelance consultant, running AYS Enterprises, specializing in printed circuit design, database solutions and utilizing Linux as a low-cost alternative to commercial operating systems and software. He has been using and promoting Linux since 1994. When not basking in the glow of a CRT, Stew enjoys time with his wife, daughter and two dogs at his future (not too much longer!) retirement home overlooking Norris Lake in the foothills of the Smokies in Tennessee.