NetServer::SMTP - basic SMTP server class for Perl


    my ($self) = NetServer::SMTP->new();
    while (<STDIN>) {
        next if (! defined($_));
        my (@vec) = split(/\s+/);
        my ($fn) = shift @vec;
        $fn = uc($fn);
        if (grep(/$fn/i, @$NetServer::SMTP::States) != 0) {
            $self->next_state_ok($fn) && do {
        } else {
              print STDERR "What on earth does [$fn][", 
                           join(" ", @vec), "] mean?\n";
        if ($self->{ERROR} > 0 ) {


A class that provides a basic SMTP server object and some methods. (Note that it doesn't provide a run method with a main execution loop -- hence the above example.)

(Net::SMTP provides a corresponding client class.)

It accepts requests in accordance with RFC 821, 4.5.1 ("Minimum Implementation"). No attempt to verify the authenticity of the sender is made; no attempt is made to filter out relay attacks or deliver the mail, and it doesn't even attempt to check messages for RFC 822 compliance. Instead, the mail is spooled in the form of a deep-frozen NetServer::SMTP object, dropped into the spool directory.

Spooled mail may be transmitted by (a) unfreezing it into a live NetServer::SMTP object and (b) invoking the send() method on it. This is the low-level delivery mechanism; it does not include a queueing mechanism.

Only one delivery method is supported in the base NetServer::SMTP class; this is dumb SMTP forwarding to a remote smarthost. Child classes derived from NetServer::SMTP may provide alternative send() methods which override this default, for example to supply local delivery methods, routing, and associated transport mechanisms for transport via UUCP or other protocols.

To-do list

RFC822 checking of incoming mail to ensure it's not totally corrupt (via Mail::Internet?).

Velocity checking implemented at the server level -- a semaphore maintains a count of children spawned/reaped, and if the spawn rate goes over a designated hot limit the server will begin issuing 421 responses.

Queued mail should be tracked via a queue database -- probably a tied DB_File. The key to each record is the position in the queue; the value is a record containing items like the number of retries (so far), the filename of the message, whether to use local or remote delivery methods, and so on. The queue is handled in a round-robin fashion by a queue delivery subroutine. Additional methods for queueing needed.

Currently, mail is stored using Freeze::Thaw to dump a frozen NetServer::SMTP object. A better solution would be to dump a Mail::Internet object and a NetServer::SMTP object containing delivery and queueing metainformation. (Expect this in release 0.02.)


NetServer::SMTP implements a rather minimalist mechanism for checking that state transactions within the SMTP protocol are valid. When entering a given state (or receiving an SMTP command), it checks the hash of arrays NetServer::SMTP::NFA; this contains a list of acceptable antecedent states for the requested command. If the current state isn't in this list, it assumes an error has occured and complains. This is just about okay for a simple program which is intended to receive and spool messages, but it is not a good basis for extension (e.g. for the implementation of a full ESMTP server architecture). In any event, state consistency checking is carried out by calling next_state_ok() -- more sophisticated servers will want to override this.

Attempts to start an ESMTP session will therefore be politely rejected.


NetServer::SMTP knows about a few standard messages, and a basic set of SMTP commands (each of which is implemented as a method):


Create a new NetServer::SMTP object. The object is now available to process incoming mail. It reads from STDIN, and writes responses to STDOUT; it should be called via NetServer::Generic.

Some initialisation parameters may be specified as a hash, or as a filehandle referring to a configuration file, or as a configuration file name.

Initialisation parameters may not be changed once the object has been created; you need to destroy it and start a new one. (Don't worry, this isn't a major overhead.)


Commence new session


Begin a new mail


Specify recipients


Send data


Reset session


Do nothing


End session (spooling mail)

These are the minimal SMTP commands required for a basic implementation of RFC 821. Each command is handled via the autoloader, which knows what to do.

In addition, NetServer::SMTP knows about the following extra commands, which may not behave quite as you expect them to do:


Normally, provides help on a command.


Called by new() to initialise the new object. Initialisation keys may be specified as a hash, supplied as a parameter to the new object, or as a filename or file handle containing a frozen NetServer::SMTP object which is users to overlay the object.

Recognized keys are:


My host name (FQDN)


array of aliases for hosts users allowed to send mail


If silent, dont say hello when creating a new server (we have other reasons for creating NetServer::SMTP objects, once in a while :)


Relay hostname (FQDN)


If this flag goes non-zero, Something Bad has happened and the session should either terminate or refuse to proceed further


Directory where spooled transactions are waiting

1 POD Error

The following errors were encountered while parsing the POD:

Around line 249:

'=item' outside of any '=over'

=over without closing =back