NAME POE::Component::Server::SimpleSMTP - A simple to use POE SMTP Server. 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 . 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; 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; 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. 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. 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 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. 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; smtpd_send_success smtpd_send_failed 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 Rocco Caputo for POE::Component::Client::DNS AUTHOR Chris "BinGOs" Williams SEE ALSO POE::Component::Pluggable POE::Component::Client::DNS POE::Component::Client::SMTP RFC 2821