E-MailRelay Reference

Command line usage

The emailrelay program supports the following command-line usage:

emailrelay [<switch> [<switch> ...]]

where <switch> is:

--admin (-a)
Enables the administration interface and specifies its listening port number.
--admin-terminate (-Q)
Enables the terminate command on the admin interface.
--anonymous (-A)
Disables the smtp vrfy command and sends less verbose smtp responses.
--as-client (-q)
Runs as a client, forwarding spooled mail to <host>: equivalent to --log --no-syslog --no-daemon --dont-serve --forward --forward-to.
--as-proxy (-y)
Runs as a proxy: equivalent to --log --close-stderr --immediate --forward-to.
--as-server (-d)
Runs as a server: equivalent to --log --close-stderr.
--client-auth (-C)
Enables smtp authentication with the remote server, using the given secrets file.
--client-filter (-Y)
Specifies an external program to process messages when they are forwarded.
--client-tls (-j)
Enables tls/ssl layer for smtp client (if openssl built in).
--close-stderr (-e)
Closes the standard error stream soon after start-up.
--connection-timeout (-U)
Sets the timeout (in seconds) when connecting to a remote server (default is 40).
--debug (-g)
Generates debug-level logging if compiled-in.
--domain (-D)
Sets an override for the host's fully qualified domain name.
--dont-serve (-x)
Disables acting as a server on any port (part of --as-client and usually used with --forward).
--filter (-z)
Specifies an external program to process messages as they are stored.
--filter-timeout (-W)
Sets the timeout (in seconds) for running the --filter processor (default is 300).
--forward (-f)
Forwards stored mail on startup (requires --forward-to).
--forward-to (-o)
Specifies the remote smtp server (required by --forward, --poll, --immediate and --admin).
--help (-h)
Displays help text and exits.
--immediate (-m)
Enables immediate forwarding of messages as soon as they are received (requires --forward-to).
--interface (-I)
Defines the listening interface for incoming connections.
--log (-l)
Writes log information on standard error and syslog.
--log-time (-L)
Adds a timestamp to the logging output.
--no-daemon (-t)
Does not detach from the terminal.
--no-smtp (-X)
Disables listening for smtp connections (usually used with --admin or --pop).
--no-syslog (-n)
Disables syslog output (always overridden by --syslog).
--pid-file (-i)
Defines a file for storing the daemon process-id.
--poll (-O)
Enables polling of the spool directory for messages to be forwarded with the specified period (requires --forward-to).
--pop (-B)
Enables the pop server.
--pop-auth (-F)
Defines the pop server secrets file (default is /etc/emailrelay.auth).
--pop-by-name (-J)
Modifies the pop spool directory according to the user name (requires --pop).
--pop-no-delete (-G)
Disables message deletion via pop (requires --pop).
--pop-port (-E)
Specifies the pop listening port number (requires --pop).
--port (-p)
Specifies the smtp listening port number.
--prompt-timeout (-w)
Sets the timeout (in seconds) for getting an initial prompt from the server.
--remote-clients (-r)
Allows remote clients to connect.
--response-timeout (-T)
Sets the response timeout (in seconds) when talking to a remote server (default is 1800).
--server-auth (-S)
Enables authentication of remote clients, using the given secrets file.
--server-tls (-K)
Enables tls/ssl layer for smtp server using the given openssl certificate file (if openssl built in).
--size (-M)
Limits the size of submitted messages.
--spool-dir (-s)
Specifies the spool directory (default is /var/spool/emailrelay).
--syslog (-k)
Forces syslog output if logging is enabled (overrides --no-syslog).
--user (-u)
Names the effective user to switch to if started as root (default is daemon).
--verbose (-v)
Generates more verbose output (works with --help and --log).
--verifier (-Z)
Specifies an external program for address verification.
--version (-V)
Displays version information and exits.

Under Windows there are a few minor differences. Use --help --verbose to see the complete list.

Message store

Mail messages are stored as text files in the configured spool directory. Each message is represented as an envelope file and a content file. The envelope file contains parameters relevant to the SMTP dialogue, and the content file contains the RFC822 headers and body text.

The filenames used in the message store have a prefix of emailrelay, followed by a process-id, timestamp and sequence number, followed by envelope or content. The envelope files then have an additional suffix to implement a simple locking scheme.

The envelope file suffixes are:

Copies of the content file for delivery to local recipients will also have a local suffix.

If a message cannot be forwarded the envelope file is given a bad suffix, and the failure reason is written into the file.

Mail processing

The --filter command-line switch allows you to specify a mail pre-processor program which operates on mail messages as they pass through the E-MailRelay system. The mail pre-processor program is run as soon as the mail message has been stored in the spool directory, with the full path of the content file added onto the end of the given command line.

For example, the following command will start a proxy server on port 10025 which processes mail using the specified filter program, and then forwards the mail on to the system's default MTA (on port 25):

emailrelay --as-proxy localhost:smtp --port 10025 --no-syslog \
  --filter $HOME/myfilter --spool-dir $HOME/spool

The pre-processor program should terminate with an exit code of zero to indicate success, or a value between 1 and 99 to indicate failure. Exit codes between 100 and 107 are reserved for special processing: 100 is used to cancel all further processing of the message, and 103 has the effect of immediately expiring any --poll timer.

If the pre-processor program terminates with a non-zero exit code then the first few thousand characters of the standard output stream are searched for a line starting with << or [[ followed by >> or ]] respectively. The text in between is taken as a failure reason, and passed back to the SMTP client.

The pre-processor program can edit any part of the message's envelope file or content file: E-MailRelay remembers nothing about the message while the pre-processor is running, except the filename. But if the message is deleted by the pre-processor then E-MailRelay may be upset, so to avoid the error message use an exit code of 100.

If the pre-processor program creates completely new messages in the spool directory then they may not be processed immediately, or they may be completely ignored. To get E-MailRelay to pick up any new messages you create in the spool directory use the --poll switch, or run emailrelay --as-client from within the pre-processor program.

As an example of a simple pre-processor this shell script examines the sending client's IP address and conditionally passes the message into sendmail (using the sendmail command-line interface rather than SMTP):

#!/bin/sh
# filter.sh
content="${1}"
envelope="`echo \"${content}\" | sed 's/content/envelope.new/'`"
ip="`awk '/MailRelay-Client:/ {print $2;exit}' \"${envelope}\"`"
if test "${ip}" = "192.168.0.2"
then
	cat "${content}" | /usr/sbin/sendmail -t
	rm -f "${envelope}" "${content}"
	exit 100 # <= cancel further processing by emailrelay
fi
exit 0

The first thing this script does is convert the path of the content file which it is given, into the corresponding envelope file. It then extracts the client's IP address out of the envelope file using awk. If this matches the fixed address then it pipes the message content into sendmail, deletes the message and exits with a value of 100. The exit value of 100 tells E-MailRelay to forget the message, and not to complain about the files disappearing.

For Windows this example can be rewritten in JavaScript:

// filter.js
var content = WScript.Arguments(0) ;
var envelope = content.substr(0,content.length-7) + "envelope.new" ;
var fs = WScript.CreateObject( "Scripting.FileSystemObject" ) ;
var ts = fs.OpenTextFile( envelope , 1 , false ) ;
var e = ts.ReadAll() ;
ts.Close() ;
var re = new RegExp( "MailRelay-Client: \(.*\)" ) ;
var ip = e.match(re)[1] ;
if( ip == "192.168.0.2" )
{
	var sh = WScript.CreateObject( "Wscript.Shell" ) ;
	sh.Run( "sendmail " + content ) ; // bogus
	fs.DeleteFile( content ) ;
	fs.DeleteFile( envelope ) ;
	WScript.Quit( 100 )
}
WScript.Quit( 0 ) ;

Windows pre-processor programs written in JavaScript can be run using cscript, with an E-MailRelay --filter switch something like this:

--filter "c:/windows/system32/cscript.exe //nologo c:/program\ files/emailrelay/filter.js"

Note how the space character in the path is escaped with a backslash.

As an example of more complex processing there is a --filter script included in the distribution (emailrelay-process.sh) that does rot-13 masking of messages. This script also does some simple MIME encoding, so that the masked message appears as an attachment within a plaintext bearer message.

E-MailRelay also has a --client-filter switch that enables pre-processing of messages just before they are forwarded, rather then after they are stored. The disadvantage is that by then it is too late to notify the SMTP client of any processing failures, so in many applications using --filter is more useful.

Bear in mind the following points when writing --filter programs:

It is also possible to do message pre-processing in a separate server process by using net:<address>:<port> as the --filter or --client-filter switch parameter. E-MailRelay connects to this address and then uses a simple line-based dialog as each e-mail message is processed where it sends the full path of the message content file in one line and expects the remote process to respond with an ok line if the message is to be accepted or an error message. One advantage of using a network pre-processor compared to running a program is that the E-MailRelay server is not blocked while the messages are being pre-processed.

Address verification

By default the E-MailRelay server will accept all addresses for incoming e-mails as valid. However, this default behaviour can be modified by using an external verifier program, specified with the --verifier command-line switch, so that you get to choose which recipient addresses are accepted as valid and which are rejected.

The external verifier program is passed a command-line containing: (1) the full e-mail address as supplied by the remote client, (2) the user-name part of the address in upper-case, (3) the host-name part in upper-case, (4) the local host's fully qualified domain name in upper-case, (5) the MAIL command's FROM: address as supplied by the client or the empty string in the case of the VRFY command, (6) the IP address of the client connection, (7) the authentication mechanism used by the client (NONE if trusted), and (8) either the authentication name or the fourth field from authentication secrets file if a trusted IP address.

So, for example, a verifier script called myverifier might be run with the following command-line:

myverifier me@myhost.mydomain ME MYHOST.MYDOMAIN MYHOST.MYDOMAIN bob@other.net 192.168.0.1 LOGIN bob

The verifier program is expected to generate two lines of output on the standard output stream and then terminate with a specific exit code.

For valid non-local addresses the first line of output is ignored, the second line should be copied from the first command-line argument, and the exit value should be one.

#!/bin/sh
# address verifier -- accept all (252)
echo ""
echo $1
exit 1

For valid local addresses, where messages are to be delivered to a local mailbox, the verifier is expected to write two lines to the standard output -- the full name associated with the mailbox, and the canonical mailbox name -- and then exit with a value of zero.

#!/bin/sh
# address verifier -- accept as local (250)
echo Local Postmaster '<postmaster@localhost>'
echo postmaster
exit 0

(In practice local delivery just means that the message files in the spool directory are copied and given a .local filename suffix.)

For invalid addresses the exit value should be greater than one, and anything written to the standard output is taken as the failure reason. (Only the few few thousand characters are read from the verifier's standard output stream; any more is thrown away.)

#!/bin/sh
# address verifier -- reject as invalid (550)
echo invalid address: $1
exit 2

To indicate a temporary failure this can be changed to an exit code of 3.

#!/bin/sh
# address verifier -- reject as temporarily invalid (450)
echo address unavailable: $1
exit 3

If the exit code is 100 then the connection is aborted immediately.

#!/bin/sh
# address verifier -- abort
exit 100

In this more complete example all addresses are accepted as long as they contain an at character:

#!/bin/sh
# address verifier -- accept only if containing an at sign
address="$1"
expr "${address}" : ".*@" > /dev/null || exit 2
echo ""
echo "${address}"
exit 1 # accept

As another example, this verifier script accepts all recipient addresses by default, but rejects remote addresses if the client has bypassed authentication by connecting on a trusted IP address:

#!/bin/sh
# address verifier
address="$1"
host="$3"
local_domain="$4"
auth_mechanism="$7"
if test -z "${auth_mechanism}" ; then auth_mechanism="NONE" ; fi
if test "${auth_mechanism}" = "NONE" -a "${host}" != "${local_domain}"
then
	echo "cannot relay without authentication"
	exit 2 # reject the recipient address
fi
echo ""
echo "${address}"
exit 1 # accept the recipient address

or in JavaScript for Windows:

// verifier.js
var address = WScript.Arguments(0) ;
var host = WScript.Arguments(2) ;
var local_domain = WScript.Arguments(3) ;
var auth_mechanism = WScript.Arguments(6) ;
if( ( auth_mechanism == "NONE" || auth_mechanism == "" ) && host != local_domain )
{
	WScript.Echo( "cannot relay without authentication" ) ;
	WScript.Quit( 2 ) ;
}
WScript.Echo( "" ) ;
WScript.Echo( address ) ;
WScript.Quit( 1 ) ;

If this verifier script is used with a suitable --server-auth file then it can be used to prevent open relay without restricting authenticated clients.

If the --verifier switch parameter is of the form net:<address>:<port> then the E-MailRelay server connects to the specified verifier daemon over the network and sends verifier requests as lines with pipe-delimited fields. The expected response is another pipe-delimited line containing the same information as returned by verifier scripts but in reverse, such as 3|address unavailable or 0|postmaster|Local Postmaster <postmaster@localhost>. The inetd super-server daemon would be a convenient way to connect up the pieces in this case.

Authentication

E-MailRelay supports the SMTP AUTH extension, as defined in RFC2554, on both the server-side and client-side.

The authentication mechanisms currently supported are:

PLAIN
Passwords are stored in clear-text, sent over the network in clear-text, and are replayable. Defined in RFC2595.
LOGIN
Similar to PLAIN. Officially obsolete although widely used.
CRAM-MD5 mechanism
Passwords are not stored in clear-text, not sent over the network, and are not replayable. Defined in RFC2195.

Authentication is enabled with the --client-auth and --server-auth command-line switches. The switch parameter is the name of a secrets file, containing usernames and passwords:

emailrelay --as-server --server-auth /etc/emailrelay-clients.auth
emailrelay --as-client myisp.net:smtp --client-auth /etc/emailrelay-myisp.auth

The secrets file has a line-based format: blank lines are ignored and the hash character (#) is used for comments.

Lines have four white-space delimited fields:

The mechanism field must be LOGIN, APOP or CRAM-MD5 (case-insensitive); the client-or-server field must be client or server; the userid field is xtext-encoded user identifier; and the secret field is the xtext-encoded LOGIN password, or the CRAM-MD5 digest key.

The xtext encoding scheme is defined properly in RFC1891, but basically it says that non alphanumeric characters should be represented in hexadecimal as +XX.

The client-side secrets file specified with --client-auth is used when E-MailRelay acts as a client to talk to a remove server. The file should contain at least one LOGIN client or CRAM-MD5 client entry.

A server-side secrets file specified with --server-auth is used when a remote client tries to authenticate with the E-MailRelay server. The file should normally contain several LOGIN server or CRAM-MD5 server entries, one for each client.

The same secrets file may be specified for both --client-auth and --server-auth switches.

The CRAM-MD5 keys can be generated using the emailrelay-passwd utility.

As an example, the following secrets file defines jsmith as the username to be used when E-MailRelay authenticates with a remote SMTP server, and defines two usernames (user1 and user2) which can be used by clients when they authenticate with the E-MailRelay server:

#
# emailrelay secrets file
#
LOGIN client jsmith my+20password
LOGIN server user1 secret
LOGIN server user2 e+3Dmc2

A CRAM-MD5 version would look like this:

#
# emailrelay secrets file
#
CRAM-MD5 client jsmith 688498119.2977922305.1278051807.3015243256.2216875978.2833592318.2902375592.3156808220
CRAM-MD5 server user1 4059553961.2316091643.3282746241.1444639637.3735501773.3404060330.2760590371.1201092398
CRAM-MD5 server user2 2798539199.3144534242.3784876256.2879973305.2327113479.216533878.2436460291.2361831919

When using the LOGIN mechanism you have to store plaintext passwords in a file. This is a bad thing. You should at least make sure that the secrets file has tight permissions, and that the passwords in it are not also used for anything important.

On the server side authentication is advertised by E-MailRealy in the response to the SMTP EHLO command if the --server-auth command-line switch is used. Authentication by the client is then mandatory unless the client's IP address is configured as a trusted address.

Trusted IP addresses are configured with lines in the secrets file having NONE in the first field, server in the second field, a wildcarded IP address in the third field, and an arbitrary keyword in the fourth field. The keyword field is passed to any external address verifier program specified by the --verifier command-line switch; it is not used for any other purpose.

For example, this secrets file allows any client connecting from the 192.168.0.0/24 domain to connect without authentication desipte the --server-auth switch:

#
# emailrelay secrets file
#
NONE server 192.168.0.* localdomain
LOGIN server user1 secret
LOGIN server user2 e+3Dmc2

On the client side authentication is performed when E-MailRelay has connected to a server which implements the AUTH extension with one of the supported mechanisms. If client authentication is enabled (with the --client-auth switch) but the remote server does not support the AUTH extension, or does not support the LOGIN or CRAM-MD5 mechanism, then E-MailRelay will log an error and not forward any messages.

If E-MailRelay successfully authenticates with the remote server then the client's authentication name (if any) is passed as a parameter to the MAIL command when the message is forwarded. Some SMTP servers are reported to reject the message if the name on the MAIL command does not match the name used to authenticate with them. However, the name passed as a parameter to the MAIL command is stored in the message's envelope file, so a --filter script can be used to change this to match whatever the remote server expects. An example script is provided in the distribution.

Note that some ISPs require separate POP/IMAP authentication before SMTP access from a particular IP address is allowed. This type of POP-before-SMTP authentication can be done outside the E-MailRelay system by POP/IMAP utilities such as fetchmail.

Pop server

E-MailRelay can be used as a POP3 server so that POP clients have access to spooled messages.

The following command-line switches are used:

--pop
Enables the POP3 server.
--pop-port <port>
Changes the POP3 listening port from its default of 110.
--pop-auth <path>
Changes the authentication secrets file. The default is typically /etc/emailrelay.auth.

The format of the authentication secrets file is the same as for --server-auth and the same file can be used for both SMTP and POP3 authentication.

APOP server entries are used for APOP authentication, LOGIN server entries are used for USER/PASS authentication, and CRAM-MD5 entries are used for AUTH authentication.

Note that the basic POP3 protocol defines only APOP and USER/PASS authentication, so some POP client programs may not be able to cope with CRAM-MD5 authentication using the POP3 AUTH extension.
--pop-by-name
Modifies the POP spool directory according to the name used by the client to authenticate with the E-MailRelay server. The client name is used as a sub-directory off the standard spool directory. So, for example, if a client authenticates as bob then the POP3 server will serve messages from the bob sub-directory, /var/spool/emailrelay/bob.

If E-MailRelay finds only the envelope file in the sub-directory and not the content file then it will look for the content file in the main spool directory, eg. /var/spool/emailrelay. This feature can be used to save disk space if serving the same message to multiple POP clients.
--pop-no-delete
Disables message deletion: the POP3 DELE command will appear to succeed, but no files will be deleted from the spool directory.

Security issues

A significant security concern is the use of external mail pre-processors and address verifiers (using the --filter and --verifier switches), and so the following precautions are taken:

effective userid
Suid privileges are revoked at start-up, switching the effective userid/groupid to be the real userid/groupid values. If started as root then the effective userid/groupid are switched at start-up to those of user daemon. Special privileges are only reclaimed when needed to bind sockets and do file i/o. Normally this means temporarily switching the userid and groupid back to what they were at start-up. However, when writing spool files after being started as root only the effective userid is changed, not the groupid, so that new files have group ownership corresponding to the daemon user.
execution environment
The mail pre-processor runs with an almost empty set of environment variables (PATH and IFS), and with no open file descriptors other than stdin and stderr open onto /dev/null, and stdout open onto a pipe.
configuration
The mail pre-processor filename has to be configured using a full path, so there is no dependence on the current working directory or the PATH environment variable.

Some other points to note are:

umask
The program runs for most of the time with a umask of 177, switching to 117 when creating spool files.
buffer overflow
Strings are dynamically allocated, so buffer overflow/truncation issues are avoided.
remote clients
By default connections will be rejected if they come from remote machines.
remote configuration
No configuration parameters can be changed through the administrative interface.
use of exec() and system()
No exec(), system() or popen() calls are used other than execve() to spawn the mail pre-processor and/or address verifier.
file permissions
After a normal installation the spool directory is has ownership of root.daemon with permissions of -rwxrwxr-x and messages files are created with permissions of -rw-rw----. This allows normal users to list messages files but not read them.

The emailrelay-submit program is given group ownership of daemon with its group set-user-id flag set. This allows it to create message files in the spool directory, and the files created end up owned by the submitter but with group ownership of daemon.
logging
Logging output is conditioned so that ANSI escape sequences cannot appear in the log.

Passwords and message content are not logged (except if using the --debug switch with debug logging support enabled at build time).
information leakage
The --anonymous switch can be used to slightly reduce the amount of information released to remote clients.

Security issues which relate to the SMTP protocol itself are beyond the scope of this document, but RFC2821 makes the following observation: "SMTP mail is inherently insecure in that it is feasible for even [..] casual users to [..] create messages that will trick a [..] recipient into believing that they came from somewhere else. [..] Real [..] security lies [..] in end-to-end methods [..] such as those which use digital signatures."

The Authentication section below also relates to security.

Administration interface

If enabled with the --admin command line switch, the E-MailRelay server will provide a network interface for performing administration tasks. This is a simple command-line interface which is compatible with telnet:

$ emailrelay --as-server --port 125 --forward-to localhost:25 --admin 10026
$ telnet localhost 10026
E-MailRelay> help
E-MailRelay> quit

The flush command is used to get the E-MailRelay server to forward spooled mail to the next SMTP server, as an alternative to running emailrelay --as-client as a separate process. In proxy mode it is a way of getting the proxy server to scan the spool-directory for new messages.

The list command lists the messages in the spool directory, info provides network status information and activity statistics, and notify enables asynchronous event notification.

Files and directories

Following a normal build from source, a make install puts files in the following locations:

This directory structure is constrained by the GNU/autoconf conventions rather than the Filesystem Hierarchy Standard (FHS).

To force FHS compliance you can use the --enable-fhs switch when running configure. This results in the following file locations:

For finer control of the directory structure the following can be specified on the configure command-line:

For example, running ./configure --prefix=/usr e_spooldir=/tmp/spool will create the GNU-style directory structure under /usr rather than /usr/local, and create the E-MailRelay spool directory as /tmp/spool rather than /usr/local/var/spool/emailrelay.

The default spool directory path which is built into the executables and scripts comes from configure via the makefiles.

Even though the --enable-fhs switch overrides all other directory specifiers during the build process, it is still possible to change the installation root directory using make install DESTDIR=<root> or DESTDIR=<root> make -e install. But note that this will not affect the default spool directory path built into the scripts and executables so the correct spool directory will have to be specified at run-time with the --spool-dir switch.

If building the configuration GUI then you may need to set the PKG_CONFIG_PATH environment variable to point to the .pc files in the Qt lib directory and set the e_qtmoc configure variable to point to the Qt moc utility. You may also need to set the correct library directory for Qt if it is wrong in the .pc file by setting LDFLAGS:

export QT=/usr/local/qt4
LDFLAGS=-L$QT/lib PKG_CONFIG_PATH=$QT/lib ./configure --enable-gui e_qtmoc="$QT/bin/moc"



Copyright (C) 2001-2008 Graeme Walker <graeme_walker@users.sourceforge.net>. All rights reserved.