NAME

    POE::Component::Server::SimpleSMTP - A simple to use POE SMTP Server.

VERSION

    version 1.52

SYNOPSIS

      # A simple SMTP Server 
      use strict;
      use POE;
      use POE::Component::Server::SimpleSMTP;
    
      my $hostname = 'mymailserver.local';
      my $relay; # specify a smart 'relay' server if required
      
      POE::Component::Server::SimpleSMTP->spawn(
            hostname => $hostname,
            relay    => $relay,
      );
    
      $poe_kernel->run();
      exit 0;

DESCRIPTION

    POE::Component::Server::SimpleSMTP is a POE component that provides an
    ease to use, but fully extensible SMTP mail server, that is reasonably
    compliant with RFC 2821 http://www.faqs.org/rfcs/rfc2821.html.

    In its simplest form it provides SMTP services, accepting mail from
    clients and either relaying the mail to a smart host for further
    delivery or delivering the mail itself by querying DNS MX records.

    One may also disable simple functionality and implement one's own SMTP
    handling and mail queuing. This can be done via a POE state interface
    or via POE::Component::Pluggable plugins.

CONSTRUCTOR

    spawn

      Takes a number of optional arguments:

        'alias', set an alias on the component;
        'address', bind the listening socket to a particular address;
        'port', listen on a particular port, default is 25;
        'options', a hashref of POE::Session options;
        'hostname', the name that the server will identify as in 'EHLO';
        'version', change the version string reported in 220 responses;
        'relay', specify a 'smart host' to send received mail to, default is
                 to deliver direct after determining MX records;
        'relay_auth', ESMTP Authentication to use, currently only PLAIN is supported, which is the default;
        'relay_user', the username required for authenticated relay;
        'relay_pass', the password required for authenticated relay;
        'time_out', alter the timeout period when sending emails, default 300 seconds;
        'maxrelay', maximum number of concurrent outgoing emails, defaults to 5;
        'domains', an arrayref of domain/hostnames that we will accept mail for;
        'origin', set to a true value to enable the stripping of Received headers;

      These optional arguments can be used to enable your own SMTP
      handling:

        'simple', set this to a false value and the component will no 
                  longer handle SMTP processing; 
        'handle_connects', set this to a false value to stop the component sending
                  220 responses on client connections;

      In simple mode one may also specify recipient handlers. These are
      regular expressions that are applied to each recipient of a recieved
      email. If a recipient matches the handler, it is removed from the
      process queue and dispatched instead to indicated session/event
      combo.

        'handlers', an arrayref containing hashrefs. Each hashref should contain the keys:
      
              'match', a regexp to apply;
              'session', The session to send the email to;
              'event', The event to trigger;

      You may also enable DNSBL lookups of connecting clients with the
      following options:

        'dnsbl_enable', set to a true value to enable DNSBL support;
        'dnsbl', set to a DNSBL to query, default is zen.spamhaus.org;

      DNSBL support uses POE::Component::Client::DNSBL to make blacklist
      queries for each connecting client. If a client is found in the
      blacklist, any further interaction with the client is denied.

      You may also enable sender verification, this does a simple MX DNS
      lookup on the domain of the email sender. If there is no MX domain
      record (ie. an NXDOMAIN) then a 550 is issued. In the case of a
      SERVFAIL, a 451 is issued. In both cases the email transaction is
      cancelled.

        'sender_verify', set to a true value to enable sender verification;

      See OUTPUT EVENTS below for information on what a handler event
      contains.

      Returns a POE::Component::Server::SimpleSMTP object.

METHODS

    session_id

      Returns the POE::Session ID of the component.

    shutdown

      Terminates the component. Shuts down the listener and disconnects
      connected clients.

    send_event

      Sends an event through the component's event handling system.

    send_to_client

      Send some output to a connected client. First parameter must be a
      valid client id. Second parameter is a string of text to send.

    data_mode

      Takes one argument a valid client ID. Switches the client connection
      to data mode for receiving an mail message. This should be done in
      response to a valid DATA command from a client if you are doing your
      own SMTP handling.

      You will receive an 'smtpd_data' event when the client has finished
      sending data. See below.

      Optionally, you may supply a filehandle as a second argument. Any
      data received from the client will be written to the filehandle. You
      will receive an 'smtpd_data_fh' event when the client has finished
      sending data.

    getsockname

      Access to the POE::Wheel::SocketFactory method of the underlying
      listening socket.

    get_handlers

      Returns an arrayref of the current handlers.

    set_handlers

      Accepts an arrayref of handler hashrefs ( see spawn() for details ).

    mail_queue

      Returns a list of hashrefs relating to items in the current mail
      queue ( when in simple mode ).

    pause_queue

      Pauses the processing of the mail queue. Any currently processing
      emails will be allowed to finish.

    resume_queue

      Resumes the processing of the mail queue.

    paused

      Indicates whether the mail queue is paused or not.

    cancel_message

      Takes one mandatory parameter a msg_id to remove from the mail queue.

    start_listener

      Takes no arguments, start the socket listener if it has stopped for
      any reason. Will fail if the listener is already erm listening.

    enqueue

      Takes one argument, a hashref with the following keys and values.
      Enqueues the item and requests that the mail queue be processed.
      Returns undef on failure or 1 on success.

        'from', the email address of the sender (required);
        'rcpt', an arrayref of the email recipients (required);
        'msg', string representation of the email headers and body (required);
        'ts', the unix time representation of the time the email was received (default is now);
        'uid', the Message-ID (default is to generate one for you);

INPUT EVENTS

    These are events that the component will accept:

    register

      Takes N arguments: a list of event names that your session wants to
      listen for, minus the 'smtpd_' prefix, ( this is similar to
      POE::Component::IRC ).

      Registering for 'all' will cause it to send all SMTPD-related events
      to you; this is the easiest way to handle it.

    unregister

      Takes N arguments: a list of event names which you don't want to
      receive. If you've previously done a 'register' for a particular
      event which you no longer care about, this event will tell the SMTPD
      to stop sending them to you. (If you haven't, it just ignores you. No
      big deal).

    shutdown

      Terminates the component. Shuts down the listener and disconnects
      connected clients.

    send_event

      Sends an event through the component's event handling system.

    send_to_client

      Send some output to a connected client. First parameter must be a
      valid client ID. Second parameter is a string of text to send.

    start_listener

      Takes no arguments, start the socket listener if it has stopped for
      any reason. Will fail if the listener is already erm listening.

OUTPUT EVENTS

    The component sends the following events to registered sessions:

    smtpd_registered

      This event is sent to a registering session. ARG0 is
      POE::Component::Server::SimpleSMTP object.

    smtpd_listener_failed

      Generated if the component cannot either start a listener or there is
      a problem accepting client connections. ARG0 contains the name of the
      operation that failed. ARG1 and ARG2 hold numeric and string values
      for $!, respectively.

    smtpd_connection

      Generated whenever a client connects to the component. ARG0 is the
      client ID, ARG1 is the client's IP address, ARG2 is the client's TCP
      port. ARG3 is our IP address and ARG4 is our socket port.

      If 'handle_connects' is true ( which is the default ), the component
      will automatically send a 220 SMTP response to the client.

    smtpd_disconnected

      Generated whenever a client disconnects. ARG0 is the client ID.

    smtpd_cmd_*

      Generated for each SMTP command that a connected client sends to us.
      ARG0 is the client ID. ARG1 .. ARGn are any parameters that are sent
      with the command. Check the RFC http://www.faqs.org/rfcs/rfc2821.html
      for details.

      If simple is true ( which is the default ), the component deals with
      client commands itself.

    smtpd_data

      Generated when a client sends an email.

        ARG0 will be the client ID;
        ARG1 an arrayref of lines sent by the client, stripped of CRLF line endings;

      If simple is true ( which is the default ), the component will deal
      with receiving data from the client itself.

    smtpd_data_fh

      Generated when a client sends an email and a filehandle has been
      provided.

        ARG0 will be the client ID;

      If simple is true ( which is the default ), the component will deal
      with receiving data from the client itself.

    smtpd_dnsbl

      Generated when a DNSBL lookup is completed, in simple mode.

        ARG0 will be the client ID;
        ARG1 will be the response sent to the client, either a 220 or 554;
        ARG2 will be a hashref with the following keys:
      
          'response', the status returned by the DNSBL, it will be NXDOMAIN if the address given was okay;
          'reason', if an address is blacklisted, this may contain the reason;
          'error', if something goes wrong with the DNS lookup the error string will be contained here;
          'dnsbl', the DNSBL that was used for this request;

    smtpd_fverify

      Generated when a sender verification fails, in simple mode.

        ARG0 will be the client ID;
        ARG1 will be the response sent to the client;
        ARG2 will be the DNS error reason;

    In simple mode these events will be generated:

    smtpd_message_queued

      Generated whenever a mail message is queued.

        ARG0 is the client ID;
        ARG1 is the mail from address;
        ARG2 is an arrayref of recipients;
        ARG3 is the email unique idenitifer;
        ARG4 is the number of lines of the message;
        ARG5 is the subject line of the message, if applicable

    smtpd_send_success

      Generated whenever a mail message is successfully delivered.

        ARG0 is the email unique identifier;

    smtpd_send_failed

      Generated whenever a mail message is unsuccessfully delivered. This
      can be for a variety of reasons. The poco will attempt to resend the
      message on non-fatal errors ( such as an explicit denial of delivery
      by the SMTP peer ), for up to 4 days.

        ARG0 is the email unique identifier;
        ARG1 is a hashref as returned by POE::Component::Client::SMTP via 'SMTP_Failure'

    Handler events are generated whenever a recipient matches a given
    regexp. ARG0 will contain a hashref representing the email item with
    the following keys:

      'uid', the Message-ID;
      'from', the email address of the sender;
      'rcpt', an arrayref of the email recipients;
      'msg', string representation of the email headers and body;
      'ts', the unix time representation of the time the email was received;

PLUGINS

    POE::Component::Server::SimpleSMTP utilises POE::Component::Pluggable
    to enable a POE::Component::IRC type plugin system.

 PLUGIN HANDLER TYPES

    There are two types of handlers that can registered for by plugins,
    these are

    SMTPD

      These are the 'smtpd_' prefixed events that are generated. In a
      handler arguments are passed as scalar refs so that you may mangle
      the values if required.

    SMTPC

      These are generated whenever a response is sent to a client. Again,
      any arguments passed are scalar refs for manglement. There is really
      on one type of this handler generated 'SMTPC_response'

 PLUGIN EXIT CODES

    Plugin handlers should return a particular value depending on what
    action they wish to happen to the event. These values are available as
    constants which you can use with the following line:

      use POE::Component::Server::SimpleSMTP::Constants qw(:ALL);

    The return values have the following significance:

    SMTPD_EAT_NONE

      This means the event will continue to be processed by remaining
      plugins and finally, sent to interested sessions that registered for
      it.

    SMTP_EAT_CLIENT

      This means the event will continue to be processed by remaining
      plugins but it will not be sent to any sessions that registered for
      it. This means nothing will be sent out on the wire if it was an
      SMTPC event, beware!

    SMTPD_EAT_PLUGIN

      This means the event will not be processed by remaining plugins, it
      will go straight to interested sessions.

    SMTPD_EAT_ALL

      This means the event will be completely discarded, no plugin or
      session will see it. This means nothing will be sent out on the wire
      if it was an SMTPC event, beware!

 PLUGIN METHODS

    The following methods are available:

    pipeline

      Returns the POE::Component::Pluggable::Pipeline object.

    plugin_add

      Accepts two arguments:

        The alias for the plugin
        The actual plugin object

      The alias is there for the user to refer to it, as it is possible to
      have multiple plugins of the same kind active in one
      POE::Component::Server::SimpleSMTP object.

      This method goes through the pipeline's push() method.

       This method will call $plugin->plugin_register( $nntpd )

      Returns the number of plugins now in the pipeline if plugin was
      initialized, undef if not.

    plugin_del

      Accepts one argument:

        The alias for the plugin or the plugin object itself

      This method goes through the pipeline's remove() method.

      This method will call $plugin->plugin_unregister( $nntpd )

      Returns the plugin object if the plugin was removed, undef if not.

    plugin_get

      Accepts one argument:

        The alias for the plugin

      This method goes through the pipeline's get() method.

      Returns the plugin object if it was found, undef if not.

    plugin_list

      Has no arguments.

      Returns a hashref of plugin objects, keyed on alias, or an empty list
      if there are no plugins loaded.

    plugin_order

      Has no arguments.

      Returns an arrayref of plugin objects, in the order which they are
      encountered in the pipeline.

    plugin_register

      Accepts the following arguments:

        The plugin object
        The type of the hook, SMTPD or SMTPC
        The event name(s) to watch

      The event names can be as many as possible, or an arrayref. They
      correspond to the prefixed events and naturally, arbitrary events
      too.

      You do not need to supply events with the prefix in front of them,
      just the names.

      It is possible to register for all events by specifying 'all' as an
      event.

      Returns 1 if everything checked out fine, undef if something's
      seriously wrong

    plugin_unregister

      Accepts the following arguments:

        The plugin object
        The type of the hook, SMTPD or SMTPC
        The event name(s) to unwatch

      The event names can be as many as possible, or an arrayref. They
      correspond to the prefixed events and naturally, arbitrary events
      too.

      You do not need to supply events with the prefix in front of them,
      just the names.

      It is possible to register for all events by specifying 'all' as an
      event.

      Returns 1 if all the event name(s) was unregistered, undef if some
      was not found.

 PLUGIN TEMPLATE

    The basic anatomy of a plugin is:

            package Plugin;
    
            # Import the constants, of course you could provide your own 
            # constants as long as they map correctly.
            use POE::Component::Server::SimpleSMTP::Constants qw( :ALL );
    
            # Our constructor
            sub new {
                    ...
            }
    
            # Required entry point for plugins
            sub plugin_register {
                    my( $self, $smtpd ) = @_;
    
                    # Register events we are interested in
                    $smtpd->plugin_register( $self, 'SMTPD', qw(all) );
    
                    # Return success
                    return 1;
            }
    
            # Required exit point for pluggable
            sub plugin_unregister {
                    my( $self, $smtpd ) = @_;
    
                    # Pluggable will automatically unregister events for the plugin
    
                    # Do some cleanup...
    
                    # Return success
                    return 1;
            }
    
            sub _default {
                    my( $self, $smtpd, $event ) = splice @_, 0, 3;
    
                    print "Default called for $event\n";
    
                    # Return an exit code
                    return SMTPD_EAT_NONE;
            }

CAVEATS

    This module shouldn't be used as is, as a production SMTP server, as
    the message queue is implemented in memory. *ouch*

TODO

    Design a better message queue so that messages are stored on disk.

KUDOS

    George Nistoric for POE::Component::Client::SMTP and
    POE::Filter::Transparent::SMTP.

    Rocco Caputo for POE::Component::Client::DNS

SEE ALSO

    POE::Component::Pluggable

    POE::Component::Client::DNS

    POE::Component::Client::SMTP

    RFC 2821 http://www.faqs.org/rfcs/rfc2821.html

AUTHOR

    Chris Williams <chris@bingosnet.co.uk>

COPYRIGHT AND LICENSE

    This software is copyright (c) 2020 by Chris Williams.

    This is free software; you can redistribute it and/or modify it under
    the same terms as the Perl 5 programming language system itself.