General-Purpose Mail Filter
mtasim— a testing tool
mtasim utility is a MTA simulator for testing
mailfromd filter scripts. By default it operates in
stdio mode, similar to that of
sendmail -bs. In this
mode it reads SMTP commands from standard input and sends
its responses to the standard output. There is also another mode,
called daemon, where
mtasim opens a TCP
socket and listens on it much like any MTA does. In both
modes no actual delivery is performed, the tool only simulates the
actions an MTA would do and responses it would give.
This tool is derived from the program
mta, which I wrote
for GNU Anubis test suite.
mtasiminteractive mode mode
If you start
mtasim without options, you will see the
220 mtasim (mailfromd 8.11) ready (mtasim) _
The first line is an usual RFC 2821 reply. The second one is
a prompt, indicating that
mtasim is in interactive mode and
ready for input. The prompt appears only if the package is compiled
with GNU Readline and
mtasim determines that its standard
input is connected to the terminal. This is called interactive
mode and is intended to save the human user some typing by offering
line editing and history facilities (see Command Line Editing in GNU Readline Library). If the package
is compiled without GNU Readline, you will see:
220 mtasim (mailfromd 8.11) ready _
where ‘_’ represents the cursor. Whatever the mode,
mtasim will wait for further input.
The input is expected to consist of valid SMTP commands
mtasim statements. The utility will act exactly
like a RFC 2821-compliant MTA, except that it will
not do actual message delivery or relaying. Try typing
get the list of supported commands. You will see something similar
250-mtasim (mailfromd 8.11); supported SMTP commands: 250- EHLO 250- HELO 250- MAIL 250- RCPT 250- DATA 250- HELP 250- QUIT 250- HELP 250 RSET
You can try a simple SMTP session now:
220 mtasim (mailfromd 8.11) ready (mtasim) ehlo localhost 250-pleased to meet you 250 HELP (mtasim) mail from: <me@localhost> 250 Sender OK (mtasim) rcpt to: <him@domain> 250 Recipient OK (mtasim) data 354 Enter mail, end with `.' on a line by itself (mtasim) . 250 Mail accepted for delivery (mtasim) quit 221 Done
mtasim does no domain checking, so such thing
as ‘rcpt to: <him@domain>’ was eaten without complaints.
So far so good, but what all this has to do with
mailfromd? Well, that’s what we are going to explain. To
mtasim consult any milter, use --port
(-X) command line option. This option takes a single
argument that specifies the milter port to use. The port can be given
either in the usual Milter format (See milter port specification,
for a short description), or as a full sendmail.cf style
X command, in which case it allows to set timeouts as well:
$ mtasim --port=inet:999@localhost # This is also valid: $ mtasim --port='mailfrom, S=inet:999@localhost, F=T, T=C:100m;R:180s'
If the milter is actually listening on this port,
will connect to it and you will get the following initial prompt:
220-mtasim (mailfromd 8.11) ready 220 Connected to milter inet://localhost:999 (mtasim)
Notice, that it makes no difference what implementation is listening
on that port, it may well be some other filter, not necessarily
However, let’s return to
mailfromd. If you do not want to
connect to an existing
mailfromd instance, but prefer
instead to create a new one and run your tests with it (a preferred
way, if you already have a stable filter running but wish to test a
new script without disturbing it), use --port=auto. This
mtasim to do the following:
mailfromd. The arguments and options for that instance may be given in the invocation of
mtasimafter a double-dash marker (‘--’)
mtasim exits, it terminates the subsidiary
mailfromd process and removes the temporary directory it has
created. For example, the following command will start
mailfromd -I. -I../mflib test.rc:
$ mtasim -Xauto -- -I. -I../mflib test.rc 220-mtasim (mailfromd 8.11) ready 220 Connected to milter unix:/tmp/mtasim-j6tRLC/socket (mtasim)
The /tmp/mtasim-j6tRLC directory and any files within it will
exist as long as
mtasim is running and will be removed when
you exit from it.28 You can also instruct the subsidiary
mailfromd to use this directory as its state directory
(see statedir). This is done by --statedir command line
$ mtasim -Xauto --statedir -- -I. -I../mflib test.rc
(notice that --statedir is the
therefore it must appear before ‘--’)
Special care should be taken when using
mtasim from root
account, especially if used with -Xauto and
mailfromd utility executed by it
will switch to privileges of the user given in its configuration
(see Starting and Stopping) and will not be able to create data in
its state directory, because the latter was created using ‘root’
as owner. To help in this case,
--user and --group command line options, that have
the same meaning as for
Now, let’s try
HELP command again:
250-mtasim (mailfromd 8.11); supported SMTP commands: 250- EHLO 250- HELO 250- MAIL 250- RCPT 250- DATA 250- HELP 250- QUIT 250- HELP 250- RSET 250-Supported administrative commands: 250- \Dname=value [name=value...] Define Sendmail macros 250- \Ecode Expect given SMTP reply code 250- \L[name] [name...] List macros 250- \Uname [name...] Undefine Sendmail macros 250 \Sfamily hostname address [port] Define sender socket address
While the SMTP commands do not need any clarification, some words about the administrative commands are surely in place. These commands allow to define, undefine and list arbitrary Sendmail macros. Each administrative command consists of a backslash followed by a command letter. Just like SMTP ones, administrative commands are case-insensitive. If a command takes arguments, the first argument must follow the command letter without intervening whitespace. Subsequent arguments can be delimited by arbitrary amount of whitespace.
For example, the
\D command defines Sendmail macros:
(mtasim) \Dclient_addr=192.168.10.1 f=sergiusz@localhost i=testmsg (mtasim)
mailfromd does not send any response to the
command, except if there was some syntactic error, in which case it
will return a ‘502’ response.
Now, you can list all available macros:
(mtasim) \L 220-client_addr=192.168.10.1 220-f=sergiusz@localhost 220 i=testmsg (mtasim)
or just some of them:
(mtasim) \Lclient_addr 220 client_addr=192.168.10.1 (mtasim)
To undefine a macro, use
(mtasim) \Ui (mtasim) \l 220-client_addr=192.168.10.1 220 f=sergiusz@localhost (mtasim)
\S command declare sender socket and host name. These
parameters are passed to the
connect handler, if one is
declared (see connect handler). To give you a chance to use this
mtasim does not invoke
connect handler right
after connecting to the milter. Instead it waits until either the
\S command or any SMTP command (except ‘HELP’)
is given. After calling
connect handler the
disabled (to reflect it, it also disappears from the
\S command takes 1 to 4 arguments. The first argument
supplies the socket family (see Table 4.3). Allowed values
are: ‘stdio’, ‘unix’, ‘inet’, ‘inet6’ or
numbers from ‘0’ to ‘3’.
\S stdio (or
\S 0) command needs no additional
arguments. It indicates that the SMTP connection is
obtained from the standard input. It is the default if sender socket
is not declared explicitly.
\S unix indicates that the connection is accepted
from a UNIX socket. It requires two more argument. The first one
supplies sender host name and the second one supplies full
path name of the socket file. For example:
\S unix localhost /var/run/smtp.sock
\S inet and
\S inet6 indicate that the
connection came from an ‘INET’ IPv4 or IPv6 socket,
correspondingly29. They require all
four arguments to be specified. The additional arguments are:
host name, IP address, and port number, in that order. For example:
\S inet relay.gnu.org.ua 188.8.131.52 34567
\S inet6 relay.gnu.org.ua 2001:470:1f0a:1be1::2 34567
Sender socket address can also be configured from the command line (see sender-socket).
Now, let’s try a real-life example. Suppose you wish to test the
greylisting functionality of the filter script described in Filter Script Example. To do this, you start
$ mtasim -Xauto -- -I. -I../mflib test.rc 220-mtasim (mailfromd 8.11) ready 220 Connected to milter unix:/tmp/mtasim-ak3DEc/socket (mtasim)
The script in test.rc needs to know
so you supply it to
Now, you try an SMTP session:
(mtasim) ehlo yahoo.com 250-pleased to meet you 250 HELP (mtasim) mail from: <firstname.lastname@example.org> 250 Sender OK (mtasim) rcpt to: <gray@localhost> 450 4.7.0 You are greylisted for 300 seconds
OK, this shows that the greylisting works. Now quit the session:
(mtasim) quit 221 Done
Until now we were using
mtasim interactively. However, it
is often useful in shell scripts, for example the
test suite is written in shell and
mtasim. To avoid the
necessity to use auxiliary programs like
mtasim contains a built-in expect
feature. The administrative command
\E introduces the
SMTP code that the next command is expected to yield. For
\E250 rcpt to: <email@example.com>
mtasim that the response to
RCPT TO command
must begin with ‘250’ code. If it does,
continues execution. Otherwise, it prints an error message and
terminates with exit code 1. The error message it prints looks like:
Expected 250 but got 470
The expect code given with the
\E command may have less than
3 digits. In this case it specifies the first digits of expected
reply. For example, the command ‘\E2’ matches replies
‘200’, ‘220’, etc.
This feature can be used to automate your tests. For example, the following script tests the greylisting functionality (see the previous section):
# Test the greylisting functionality # \E220 \Dclient_addr=10.10.1.13 \E250 ehlo yahoo.com \E250 mail from: <firstname.lastname@example.org> \E450 rcpt to: <gray@localhost> \E221 quit
This example also illustrates the fact that you can use
‘#’-style comments in the
mtasim input. Such a script
can be used in shell programs, for example:
mtasim -Xauto --statedir -- -I. -I../mflib test.rc < scriptfile if $? -ne 0; then echo "Greylisting test failed" fi
It is possible to log an entire SMTP session to a file. This is called session tracing. Two options are provided for this purpose:
Sets the name of the trace file, i.e. a file to which the session
transcript will be written. Both the input commands, and the
mtasim responses are logged. If the file file exists,
it will be truncated before logging. This, however, can be changed
using the following option:
If the trace file exists, append new trace data to it.
mtasim in daemon mode, use the
--daemon (or -bd) command line option. This mode
is not quite the same as Sendmail -bd mode. When started in
mtasim selects the first available
TCP port to use from the range ‘1024 -- 65535’.
It prints the selected port number on the standard output and
starts listening on it. When a connection comes, it serves a
single SMTP session and exits immediately when it is
This mode is designed for use in shell scripts and automated test cases.
This section provides a summary of administrative commands available
Defines Sendmail macro name to the given value. Any number of name=value pairs can be given as arguments.
See D command.
mtasim to expect next SMTP command to
return given code (a three-digit decimal number).
See expect commands.
Lists defined macros. See L command.
Undefines macros given as its arguments.
Declares the sender socket parameters. See S command, for a detailed description and examples.
This command is available only at the initial stage of a
mtasim session, before the first SMTP command was
given. It is disabled if the --sender-socket option was
given in the command line (see sender-socket).
help output reflects whether or not this command is available.
If neither this command nor the --sender-socket option were
mtasim behaves as if given the
The family argument
supplies the socket family, i.e. the first argument to the
connect handler (see connect handler). It can have either
literal or numeric value, as described in the table below:
|stdio||0||Standard input/output (the MTA is run with -bs option)|
See also Table 4.3.
Depending on the family, the rest of arguments supply additional parameters:
The hostname argument can be specified. It defines the first
argument of the
connect handler (see hostname in connect handler).
All arguments must be specified.
|hostname||1||Sender host name|
|address||4||Sender IP address|
|port||3||Sender port number|
Hostname and address must be supplied. The address argument must be a full pathname of the UNIX socket.
mtasimcommand line options
This section summarizes all available
mtasim command line options.
Append to the trace file. See traces.
Set the body chunk length (bytes) for
Run as daemon. See daemon mode.
Define Sendmail macro macro to the given value. It is
similar to the
\D administrative command (see D command)
Set desired logging level for
(see Gacopyz). See gacopyz-log option, for a detailed
description of level. Notice, that unless this option is used,
the --verbose (-v) command line option implies
When switching to user’s privileges as requested by the --user command line option, retain the additional group name. Any number of --group options may be given to supply a list of additional groups.
Run with this user privileges. This option and the --group
option have effect only if
mtasim was started with root
Display a short help summary
Force using the given Milter protocol version number. The version argument is either a numeric version (e.g. ‘2’), or a version string in form ‘major.minor[.patch]’, where square brackets indicate optional part. The default is ‘1.0.0’. If version is any of ‘2’, ‘3’ or ‘1.0.0’, the default protocol capabilities and actions for that version are set automatically. This option is intended for development and testing of the Gacopyz library (see Gacopyz).
Set Milter protocol capabilities. See gacopyz/gacopyz.h for the meaning of various bits in the bitmask. Look for the C macros with the prefix ‘SMFIP_’.
Set timeouts for various Milter operations. Values is a comma-separated list of assignments ‘T=V’, where T is a timeout code, indicating which timeout to set, and V is its new value. Valid timeout codes are:
Timeout for connecting to a filter.
Timeout for sending information from the simulator to a filter.
Timeout for reading reply from the filter.
Overall timeout between sending end-of-message to filter and receiving
final acknowledgment. Indirectly, it configures the upper
limit on the execution time of the
eom handler (see eom handler).
Set Milter actions. See gacopyz/gacopyz.h for the meaning of various bits in the bitmask. Look for the C macros with the prefix ‘SMFIF_’.
Not-interactive mode (disable readline). See Command Line Editing in GNU Readline Library.
Communicate with given Milter port. See mtasim milter port.
Set readline prompt. The default prompt string is ‘(mtasim) ’.
Declare sender socket address. This option has the same effect as
S command. See S command, for a detailed discussion
and a description of its arguments.
When using -Xauto, use the temporary directory name as
mailfromd state directory (see statedir mtasim option).
Use the SMTP protocol on standard input and output. This
is the default mode for
mtasim. See interactive mode.
Set name of the trace file. See traces.
Display option summary
Increase verbosity level. Implies --gacopyz-log=debug, unless that option is used explicitly.
Print program version
However, this is true only if the program
is exited the usual way (via
QUIT or end-of-file). If it is
aborted with a signal like
SIGINTR, the temporary directory is
Depending on how
configured, ‘inet6’ may be not available.
This document was generated on May 26, 2021 using makeinfo.Verbatim copying and distribution of this entire article is permitted in any medium, provided this notice is preserved.