David Muir Sharnoff


Net::SMTP::Receive - receive mail via SMTP





        package MyMailReceiver;

        @ISA = qw(Net::SMTP::Receive);

        use Net::SMTP::Receive;

        sub deliver
                my ($message) = @_;

                # attempt to deliver a message...
                die or return, return code ignored

        sub is_delivered
                my ($message, $recipient) = @_;

                if ($recipient) {
                        return 1 if delivered to recipient
                        return 0 if not
                return 1 if message is fully delivered
                return 0 if not


Net::SMTP::Receive handles receiving email via SMTP. It is built as a base class that must be subclassed to provide methods for actually delivering a message. Many aspects of Net::SMTP::Receive's behavior can be modified by overriding methods in the subclass.

Net::SMTP::Receive does not provide any method to deliver a message or even check that it has been delivered. That's left for the subsclass. However, it will queue the message until it has been delivered.

Almost all configuration of Net::SMTP::Receive is done through overriding method definitions.

Both the SMTP server and individual messages are represented by Net::SMTP::Receive objects (or rather MyMailReceiver objects if that's what you choose to name your subclass).

This module defines the pieces you need for a basic mail server but it since some of the bits must be overriden, it does not define a complete mail server. A complete mail server, listens for connections, queues mail, re-runs the queue every now and then, and can display the queue. A call to serer() will listen for conenctions. It blocks forever. A call to runqueue() will process the pending queue. Arrange to call this periodically. A call to showqueue() will display the queue: provide a command to for users to do this. This is not meant as a high-volume mail server. It is mean to provide a way to directly receive mail in perl while honoring the guarantees that mail servers should make.


The following fields exist the sever objects and continue to exist as the server object forks itself to become a message object.


PEERADDR is the IP address of the system the email is coming from. PEERHOST is the hostname of the system the email is coming from.


IDENT is the username returned by doing an ident query on the sender.


HELO is a copy of the greeting sent by the client.


MIMETYPE is either 8BITMIME or 7BIT depending on the transfer encoding used.


FROM is the address provided with MAIL FROM.


TO is an anonymous array of addresses provided by the RCPT TO command. This array may be modified by the deliver() method.


TIME is a timestamp (integer) of when the message was first enqueued.


ID is the identification assigned to the message as it is enqueued. The filename of the message is $queue_directory/$message-{ID}.txt> (also available as $message-{TEXTFILE}>). The envelope is stored as a perl object in $queue_directory/$message-{ID}.pqf>.


TEXTFILE is the filename where the message is stored while in the message queue. Messages are placed in the queue before delivery is attempted.


ERROR contains the die message ($@) from the last delivery attempt.


LASTRUN is the timestamp (integer) of when delivery was last attempted on the message.


STATE is a status field that is left over from the protocol negotiations. It's mentioned here because it's reserved for internal use. Any additional fields added after this release will use a member data naming prefix of NSR_.


You must override deliver and is_delivered. In the context of method delivery, $message is a persistent object. You can add or change fields and unless the message is fully delivered, your changes stored with Storable and restored the next time delivery() is attempted.

See the "MEMBER DATA" section for the pre-defined keys that the message object provides.

For is_delivered the recipient optional. If present, the return value is used for for showqueue.

For deliver, it is okay to die. If you do, the die message will become the ERROR field and be displayed by showqueue. Delivery will be re-attempted by runqueue.


The following is not a complete set, but it is likely to be enough. For the complete set, read the source.

check_rcptto() is an important method to define. It is here that it is easiest to prevent open relaying. A simple check that the recipient address belongs to you will do. A return code of something like: "550 relaying denied" works.

        sub check_rcptto
                my ($self, $envelope_to_address) = @_;

                return 0 if the address is okay as it stands
                return (0, @replacement_addresses) if the address is okay
                        but delivery should be redirected to antoher 
                        address or addresses.
                return "550 relaying denied, so go away!"

check_mailfrom is less important, but can also be useful.

        sub check_mailfrom
                my ($self, $envelope_from_address) = @_;

                return 0 if the from address is okay
                return $smtp_3digit_error_code otherwise

        sub do_syslog
                return 1 if you want syslogging of activity
                return 0 if you want errors to stderr

        sub queue_directory 
                return '/var/spool/pmqueue';
                # return something else to place the message queue
                # elsewhere.

        sub checkaccess
                my ($self, $client_iohandle, $remote_ident) = @_;

                die or exit() if you don't want to talk to the client
                otherwise, return anything

        sub prestart
                my ($self, %config) = @_;

                # initialize any special MyMailReceiver state before
                # starting to listen as a server

        sub max_datalength
                return 20_000_000; 
                # return something smaller if you don't want to accept
                # 20GB messages..

        sub max_recipients
                return 10_000;
                # return something smaller if you want to place a more
                # reasonable limit on the number of recipients.

        sub add_envelope
                return 0; #default
                return 1 
                # if you want to add an C<X-Envelope-To:> header.
                # If you do this, C<Bcc:> won't be blind.

        sub predeliver
                my ($msg, $client, $msgref) = @_;
                # check over the incoming message before it is enqueued
                # this is a good place to enforce policy or do quick
                # spam checks.  Die with an SMTP error code to reject
                # the message --- die "500 relaying denied"
                # The $msgref is an anonymous list comprising the body
                # of the message.
                die "500 relaying denied" if $msgref->[0] !~ /\@myhost/;
                return 0


Net::SMTP::Receive has three core methods that are used to fire it up.


server() starts an SMTP listening server. The config parameters currently supported are:



runqueue() processes the mail queue. It is not called automatically by the server. Call it with a cron job instead. Be sure to do this!

        MyMailReceiver->showqueue([$message ids])

showqueue() prints a sendmail-style mail queue report to STDOUT. It is optionally restricted to particular message ids.

Net::SMTP::Receive doesn't provide much for the subclass to call. However, there are a few methods that might be some help. Well, one anyway:

        $message->log($text, $args)

syslog()s text and also printf's it.


Copyright (C) 2001, 2002 David Muir Sharnoff. License hereby granted for anyone to use, modify or redistribute this module at their own risk. Please feed useful changes back to muir@idiom.org.