How to make locally generated mail appear to come from an e-mail address in a foreign domain.
Table of Contents
In mid-2005, Galois Connections, Inc., the company for which I work, took over the care and feeding of cvs.haskell.org, the public code repository for
several significant open-source Haskell projects. All active developers
have accounts on the machine, so there are several dozen local accounts.
Whenever a developer submits a change to the repository, a backend script formats and sends an e-mail message detailing
the change for other developers interested in that section of code. Since the commit scripts run under each developer’s local
user account, the automated e-mail messages were addressed From:
<username@cvs.haskell.org>.
The problem is that neither Galois nor the developers wanted to maintain a separate cvs.haskell.org. e-mail server. Galois didn’t want the hassle of maintaining a separate mail domain, and
the developers were leary of being assigned yet another e-mail address.
Ideally, outbound messages would appear with a From header that reflected each
developer’s e-mail address of choice. Similarly, any message delivered to a local account, such as an error message from a
cron job, would be sent off to the same remote address.
The easy part of the final solution was to use aliases to ensure that mail addressed to the developers’ local accounts
would be delivered to their preferred remote e-mail address. This would ensure that error messages from cron jobs or
automated scripts would actually get read. The aliases database, typically found at /etc/mail/aliases, is well known. It’s included and populated on nearly every system that ships with
sendmail as the main mail transport agent.
Simply, each line includes the local mail alias, a colon, and the real destination for mail addressed to that local alias. The real destination may be a local account, a program (like Mailman), or, in this case, a remote e-mail address.
bob: robert.smith@hisdomain.net kate: kate@school.ac.uk
After editing the aliases file, you need to run newaliases to translate your aliases into the binary database format sendmail can read.
The tougher issue was masquerading locally generated messages, especially CVS commits, so they appeared to be from a developer’s remote e-mail address. Sendmail has long been able to masquerade local users as all coming from a single domain, but I’d never had to masquerade each local account from its own domain.
The solution lay in sendmail’s genericstable feature. The sendmail documentation says, “This feature will cause unqualified addresses (i.e., without a domain) and addresses with a domain listed in class {G} to be looked up in a map and turned into another ("generic") form, which can change both the domain name and the user name.”
Unlike the aliases feature, however, getting the genericstable feature to work will likely mean that you’ll have to modify
your sendmail.cf configuration file. For most of us, that means editing the m4 source file (typically, but not always, /etc/mail/sendmail.mc). In my case, the additions were minor:
FEATURE(`genericstable')dnl GENERICS_DOMAIN(`localhost.localdomain')dnl
The format of the genericstable file is, annoyingly, just slightly different from that used
by aliases. In this case, there are two whitespace-separated columns, the first containing the
local username, the second the remote address.
bob robert.smith@hisdomain.net kate kate@school.ac.uk
After populating /etc/mail/genericstable, it’s necessary to build the binary representation
sendmail will use:
makemap hash /etc/mail/genericstable < /etc/mail/genericstable
Any e-mail messages generated by local username bob will have their From header rewritten to
appear to be from <robert.smith@hisdomain.net>.
This article is licensed under a Creative Commons License.