Content is scrollable

Back to May 2000 meeting page

Talk for Manchester LUG
Matthew John Palmer

Sendmail - friend or foe?

Introduction

Mail configuration is a frequent stumbling block for new net admins. Not simply because the concept is hard - mail is easy, after all - but the myriad little options is the fun part.

Sendmail allows you to do it all. As such, it can seem dense and complicated. A foe. However, if we concentrate on small sections at a time, and 'divide and conquer', we can turn sendmail into our best friend.

The config options presented here will work for 8.10 and later, guaranteed. They may work for 8.9 or earlier, but I'd recommend 8.10.

Sendmail - the basics

  • Delivery occurs in the following manner:

    MUA -> MTA -> (Internet) -> MTA -> MUA

  • MUA - Mail User Agent (eg pine), MTA - Mail Transport Agent (Sendmail)
  • MTA to MTA communication via SMTP (Simple Mail Transfer Protocol)
  • MUA/MTA and MTA/MUA communication not defined by standards
  • Four points of data modification/routing/etc:
    • Sending MUA
    • Sending MTA
    • Receiving MTA
    • Receiving MUA
  • Most common place for system customisation is in the MTAs. Sendmail config.
  • Edit the sendmail.mc file, containing macros to be expanded.
  • Several types of macros available. Most used are:
    • define() - specify configuration options, like paths, addresses, etc.
    • FEATURE() - many, many weird and wonderful things you can do with sendmail.
    • OSTYPE() - OS-specific defines.
    • MAILER() - Different ways of transporting mail between the MTA and MUAs, and between the MTA and other MTAs.
    • Specifically named ones, such as MASQUERADE_AS, RELAY_DOMAIN, etc.
  • Arguments to macros should be quoted, by a backprime ` to open, and an apostrophe ' to close.
  • A lot of variables are stored in classes - for example, hosts that we accept mail for is class 'w', class 'M' has the hosts which we will masquerade, and 'R' lists domains which we will relay mail for. A full list is provided with sendmail.
  • Masquerading is the process of pretending to have a different domain name. Infinitely useful for dialup boxes.
  • Relaying receives a mail message from an MTA and forwards it to another MTA.
  • Sendmail can rewrite mail addresses any number of ways based on the config which it is given.

Sendmail - the not-so-basics

Rulesets

  • The workhorse of sendmail - almost infinitely configurable.
  • Specify translation methods.
  • Identified by name or number. Name preferred.
  • Different rulesets do different things - canonify, masquerade, etc.
  • Each rule is used in order, and is independent of all other rules.

Masquerading

  • Pretend you're somebody else! (Possible risk of Schizophrenia?)
  • Specify who we're going to pretend to be by MASQUERADE_AS(`host')
  • We will masquerade any host (or domain - see below) which is specified by MASQUERADE_DOMAIN(`host')
  • A file containing the appropriate hosts or domains can be specified with MASQUERADE_DOMAIN_FILE(`filename')
  • To exclude a host or domain from masquerading, use MASQUERADE_EXCEPTION(`host')
  • Note: we will also masquerade any host or domain which we have specified as a local host or domain by class 'w'.
  • FEATURE(`masquerade_entire_domain') will rewrite for any host which is part of the domains specified in classes 'M' or 'w'.

Relaying

  • Typically, we want to relay any mail from our local domain, or to our local domain. Anything else will leave us vulnerable to aiding and abetting a spammer.
  • To simplify mail configuration, we usually have all mail immediately transferred to a central mailer, which then rewrites it and sends it to its destination.
  • Use RELAY_DOMAIN() and RELAY_DOMAIN_FILE() to control which hosts or domains we will relay. The list is maintained in class 'R'.
  • FEATURE(`relay_hosts_only') works in a similar manner to masquerade_entire_domain, though in reverse.

Spam control

  • Only specify those domains which you definitely want to route mail for.
  • Never, ever, ever activate FEATURE(`promicuous_relay')
  • Consider activating the DNS Blackhole List - a list of known spam domains, which you can reject. FEATURE(`dnsbl'), and http://maps.vix.com/rbl.

More address rewriting - generics

  • Rewrite From: on all outgoing mail addresses to make them more palatable to the real world if we're a private network. (ie. no official namespace)
  • Uses a Generics table to provide local name -> real name mapping.
  • FEATURE(`genericstable', `file spec')
  • Default filespec is hash /etc/mail/genericstable but is possibly changed by the OSTYPE().
  • The key for each entry in the generics DB is either lusername, @domain.name, lusername@domain.name, and the value is the new address to forward it to.
  • Turn the text file into a DB file, by makemap.
  • The domain part of the lusername must be listed in class 'G', which is added to by GENERICS_DOMAIN and GENERICS_DOMAIN_FILE (as per masquerading).
  • FEATURE(`generics_entire_domain') works as per masquerading.

Virtual hosting

  • Rewrites the To: line of incoming mail to send it to the right place.
  • The key is the address which the mail is addressed to, while the value is the new address.
  • Note that all domains which appear in the keys much be part of class 'w' or class 'VirtHost'.
  • VIRTUSER_DOMAIN and VIRTUSER_DOMAIN_FILE modify class 'VirtHost'.
  • FEATURE(`virtusertable', `hash /etc/mail/virtusertable')
  • FEATURE(`virtuser_entire_domain') works as per masquerading.

Miscellaneous

  • FEATURE(`nocanonify') works well for part time links.
  • FEATURE(`nullclient', `relayhost') defines a config file which transfers absolutely everything it gets to relayhost without any masquerading, rewriting, or anything.
  • Not sendmail specific, but placing a '+' sign followed by a string gives a 'detail' which can be used by a mail filter to sort mail.

Sample Configurations

To show the power (if not abject simplicity) of Sendmail, here are a couple of sample configurations doing strange and ungainly things with mail. Feel free to use them in your own mail systems.

Mail over dialups

We're assuming some things:

  • Part time link.
  • No official addresses or namespace.
  • Local domain is domain.fake.uk.
  • Only a few users.
  • Users have POP or similar mailboxes at different domains, all of which should be collected to the local system.
    • bob@domain.fake.uk -> user1@mailhost.com
    • fred@domain.fake.uk -> user2@freemail.com
    • jane@domain.fake.uk -> user3@foo.org
  • One mail server, several clients.
  • All clients are administered by the same person (nobody has local root, in other words).
  • All hosts in the domain.fake.uk domain are resolvable (either through hosts or DNS), as well as the rest of the Internet (only when the link is up).

From these assumptions, the following config will be used:

  • Client machines should have a very simple config file:
    dnl # Set OS type to foobar - you should probably change this!
    OSTYPE(`foobar')dnl
    
    dnl # Since we're not on the Internet permenantly, don't try and lookup
    dnl # foreign names immediately.
    FEATURE(`nocanonify')dnl
    
    dnl # Forward all mail (with no exceptions) to `mail.domain.fake.uk'
    FEATURE(`nullclient', `mail.domain.fake.uk')dnl
    
  • The server is a little more complicated:
    dnl # Set OS type to foobar - you'll need to change this!
    OSTYPE(`foobar')dnl
    
    dnl # Do not transport via 'expensive' (as determined by the 'e' flag)
    dnl # mailers upon initial submission.
    define(`confCON_EXPENSIVE', `True')dnl
    
    dnl # Make the SMTP protocol (which we will use to deliver any mail not for
    dnl # the local system) an 'expensive' mailer (see above)
    define(`SMTP_MAILER_FLAGS', `+e')dnl
    
    dnl # Stop putting our hostname on mail and just put 'domain.fake.uk' by default
    define(`confDOMAIN_NAME', `domain.fake.uk')dnl
    
    dnl # Not permenantly connected to the net, so don't go looking up names all
    dnl # the time.
    FEATURE(`nocanonify')dnl
    
    dnl # Add `domain.fake.uk' to class 'm' - used for *everything* rewrite related
    MASQUERADE_DOMAIN(`domain.fake.uk')dnl
    
    dnl # Add our domain name (from confDOMAIN_NAME) to any and all mail without it
    FEATURE(`always_add_domain')dnl
    
    dnl # Rewrite both header and envelope of the mail message.
    FEATURE(`masquerade_envelope')dnl
    
    dnl # File containing all of the domains we will accept mail for
    define(`confCW_FILE', `/etc/mail/sendmail.cw')dnl
    
    dnl # Relay anything in the domain `domain.fake.uk' but not anything else.
    RELAY_DOMAIN(`domain.fake.uk')dnl
    
    dnl # Address translation for outgoing mail, with the hash database located
    dnl # in /etc/mail/outgoing.trans.db
    FEATURE(`genericstable', `hash /etc/mail/outgoing.trans.db')dnl
    
    dnl # Apply translation to anything in `domain.fake.uk'
    GENERICS_DOMAIN(`domain.fake.uk')dnl
    FEATURE(`generics_entire_domain')dnl
    
    dnl # The mailers we want to support
    MAILER(`local')dnl
    MAILER(`smtp')dnl
    
  • To have this work properly (internal mail not rewritten) we must remove the local masquerades:
    • In ruleset 10 (SEnvFromL=10) remove the line involving MasqEnv.
    • In ruleset 30 (SHdrFromL=30) remove the line involving MasqHdr.
  • There are a couple of support files needed, as well.
  • /etc/mail/outgoing.trans.txt:
    bob	user1@mailhost.com
    fred	user2@freemail.com
    jane	user3@foo.org
    
  • The list of domains we will accept mail for (/etc/mail/sendmail.cw):
    localhost
    domain.fake.uk
    
  • And a nice /etc/mail/Makefile to remake all the configs:
    SENDMAIL_CF_M4=/usr/share/sendmail/sendmail.cf/m4/cf.m4
    
    all: outgoing.trans.db sendmail.cf
    
    outgoing.trans.db: outgoing.trans.txt
    	cp outgoing.trans.db outgoing.trans.db.old
    	makemap hash outgoing.trans.db < outgoing.trans.txt
    	
    sendmail.cf: sendmail.mc
    	cp sendmail.cf sendmail.cf.old
    	m4 $(SENDMAIL_CF_M4) sendmail.mc > sendmail.cf
    
  • Just remember to run make from the /etc/mail directory.

Mail over dialups, using one external mail address

A sneaky way of doing things which only works if your mailbox provider will handle it. Check if they preserve 'detail' specifiers (username+detail form).

  • /etc/mail/sendmail.mc:
    OSTYPE(`foobar')dnl
    define(`confCON_EXPENSIVE', `True')dnl
    define(`SMTP_MAILER_FLAGS', `+e')dnl
    FEATURE(`nocanonify')dnl
    
    dnl # Class m additions
    MASQUERADE_DOMAIN(`domain.fake.uk')dnl
    FEATURE(`masquerade_entire_domain')dnl
    
    dnl # Hosts we will accept mail for
    define(`confCW_FILE', `/etc/mail/sendmail.cw')dnl
    
    dnl # Address translation for outgoing mail, with the hash database located
    dnl # in /etc/mail/outgoing.trans.db
    FEATURE(`genericstable', `hash /etc/mail/outgoing.trans.db')dnl
    
    dnl # Translate incoming mail
    FEATURE(`virtusertable', `hash /etc/mail/incoming.trans.db')dnl
    
    MAILER(`local')dnl
    MAILER(`smtp')dnl
    
  • /etc/mail/outgoing.trans.txt:
    @domain.fake.uk	realuser+%1@yourisp.com
    
  • /etc/mail/incoming.trans.txt:
    realuser+*@yourisp.com	%2@domain.fake.uk
    
  • /etc/mail/Makefile:
    SENDMAIL_CF_M4=/usr/share/sendmail/sendmail.cf/m4/cf.m4
    
    all: outgoing.trans.db incoming.trans.db sendmail.cf
    
    outgoing.trans.db: outgoing.trans.txt
    	cp outgoing.trans.db outgoing.trans.db.old
    	makemap hash outgoing.trans.db < outgoing.trans.txt
    
    incoming.trans.db: incoming.trans.txt
    	cp incoming.trans.db incoming.trans.db.old
    	makemap hash incoming.trans.db < incoming.trans.txt
    
    sendmail.cf: sendmail.mc
    	cp sendmail.cf sendmail.cf.old
    	m4 $(SENDMAIL_CF_M4) sendmail.mc > sendmail.cf
    

Multidomains

Since somebody asked especially for them, here is a mail config which will do multiple virtual domains, with all domains specified in the file /etc/mail/virtdomains. All mail for each domain will get forwarded to a mailbox called <domain>+<user>@realmail.com, and the inverse will also happen (mail from foo+fred@realmail.com will go out as being from fred@foo.com)

There are three domains we're hosting:

  • foo.com
  • bar.org
  • wombat.net

I am assuming that we have a fulltime, fully DNSd link to the Internet at large.

As as aside, this setup, as is, is untested, but it should work without a hassle.

OSTYPE(`foobar')dnl

dnl # Domains which we handle mail for
USE_CW_FILE(`/etc/mail/virtdomains')dnl

dnl # Domains we will relay from and to
RELAY_DOMAIN_FILE(`/etc/mail/virtdomains')dnl

dnl # Outgoing translation table
FEATURE(`generics_table', `hash /etc/mail/outgoing.trans.db')dnl
GENERICS_DOMAIN_FILE(`/etc/mail/virtdomains')dnl
FEATURE(`generics_entire_domain')dnl

dnl # Incoming translation table
FEATURE(`virtuser_table', `hash /etc/mail/incoming.trans.db')dnl
VIRTUSER_DOMAIN_FILE(`/etc/mail/virtdomains')dnl
FEATURE(`virtuser_entire_domain')dnl

/etc/mail/virtdomains will look like:

foo.com
bar.org
wombat.net

A sample /etc/mail/outgoing.trans.txt:

foo+*@realmail.com	%1@foo.com
bar+*@realmail.com	%1@bar.org
wombat+*@realmail.com	%1@wombat.net

Also, we will translate coming back, specified in /etc/mail/incoming.trans.txt:

@foo.com	foo+%1@realmail.com
@bar.org	bar+%1@realmail.com
@wombat.net	wombat+%1@realmail.com

Finally, an /etc/mail/Makefile to hold it all together:

SENDMAIL_CF_M4=/usr/share/sendmail/sendmail.cf/m4/cf.m4

all: outgoing.trans.db incoming.trans.db sendmail.cf

outgoing.trans.db: outgoing.trans.txt
	cp outgoing.trans.db outgoing.trans.db.old
	makemap hash outgoing.trans.db < outgoing.trans.txt

incoming.trans.db: incoming.trans.txt
	cp incoming.trans.db incoming.trans.db.old
	makemap hash incoming.trans.db < incoming.trans.txt

sendmail.cf: sendmail.mc
	cp sendmail.cf sendmail.cf.old
	m4 $(SENDMAIL_CF_M4) sendmail.mc > sendmail.cf

References

  • cf.README (or cf/README, or README.cf, or similar), Sendmail distribution.
  • Mail-Queue mini-HOWTO, Leif Erlingsson, Jan P Tietze, September 1997, LDP.
  • Virtual Hosting with Sendmail, http://www.sendmail.org/virtual-hosting.html, last accessed 19/5/2000.

Further Reading

  • RFC821, Simple Mail Transport Protocol, Jonathan B. Postel, August 1982.
  • RFC822, Standard for the Format of ARPA Internet Text Messages, David H. Crocker, August 1982.
  • Sendmail Installation and Operation Guide, Eric Allman, Sendmail distribution.
  • Sendmail, 2nd Edition, Bryan Costales, Eric Allman, O'Reilly & associates.
  • Setting up your New Domain mini-HOWTO, Christopher Neufeld, January 2000.