Implementation for issue 4184

Changes the previously private attributes to make them public, increasing the potential for extending the library in user code. Backward-compatible and documented.
diff --git a/Doc/library/smtpd.rst b/Doc/library/smtpd.rst
index 2767516..df67de9 100644
--- a/Doc/library/smtpd.rst
+++ b/Doc/library/smtpd.rst
@@ -10,10 +10,14 @@
 
 
 
-This module offers several classes to implement SMTP servers.  One is a generic
+This module offers several classes to implement SMTP (email) servers.
+
+Several server implementations are present; one is a generic
 do-nothing implementation, which can be overridden, while the other two offer
 specific mail-sending strategies.
 
+Additionally the SMTPChannel may be extended to implement very specific
+interaction behaviour with SMTP clients.
 
 SMTPServer Objects
 ------------------
@@ -26,7 +30,6 @@
    inherits from :class:`asyncore.dispatcher`, and so will insert itself into
    :mod:`asyncore`'s event loop on instantiation.
 
-
    .. method:: process_message(peer, mailfrom, rcpttos, data)
 
       Raise :exc:`NotImplementedError` exception. Override this in subclasses to
@@ -37,6 +40,11 @@
       containing the contents of the e-mail (which should be in :rfc:`2822`
       format).
 
+   .. attribute:: channel_class
+
+      Override this in subclasses to use a custom :class:`SMTPChannel` for
+      managing SMTP clients.
+
 
 DebuggingServer Objects
 -----------------------
@@ -71,3 +79,91 @@
    running this has a good chance to make you into an open relay, so please be
    careful.
 
+SMTPChannel Objects
+-------------------
+
+.. class:: SMTPChannel(server, conn, addr)
+
+   Create a new :class:`SMTPChannel` object which manages the communication
+   between the server and a single SMTP client.
+
+   To use a custom SMTPChannel implementation you need to override the
+   :attr:`SMTPServer.channel_class` of your :class:`SMTPServer`.
+
+   The :class:`SMTPChannel` has the following instance variables:
+
+   .. attribute:: smtp_server
+
+      Holds the :class:`SMTPServer` that spawned this channel.
+
+   .. attribute:: conn
+
+      Holds the socket object connecting to the client.
+
+   .. attribute:: addr
+
+      Holds the address of the client, the second value returned by
+      socket.accept()
+
+   .. attribute:: received_lines
+
+      Holds a list of the line strings (decoded using UTF-8) received from
+      the client. The lines have their "\r\n" line ending translated to "\n".
+
+   .. attribute:: smtp_state
+
+      Holds the current state of the channel. This will be either
+      :attr:`COMMAND` initially and then :attr:`DATA` after the client sends
+      a "DATA" line.
+
+   .. attribute:: seen_greeting
+
+      Holds a string containing the greeting sent by the client in its "HELO".
+
+   .. attribute:: mailfrom
+
+      Holds a string containing the address identified in the "MAIL FROM:" line
+      from the client.
+
+   .. attribute:: rcpttos
+
+      Holds a list of strings containing the addresses identified in the
+      "RCPT TO:" lines from the client.
+
+   .. attribute:: received_data
+
+      Holds a string containing all of the data sent by the client during the
+      DATA state, up to but not including the terminating "\r\n.\r\n".
+
+   .. attribute:: fqdn
+
+      Holds the fully-qualified domain name of the server as returned by
+      ``socket.getfqdn()``.
+
+   .. attribute:: peer
+
+      Holds the name of the client peer as returned by ``conn.getpeername()``
+      where ``conn`` is :attr:`conn`.
+
+   The :class:`SMTPChannel` operates by invoking methods named ``smtp_<command>``
+   upon reception of a command line from the client. Built into the base
+   :class:`SMTPChannel` class are methods for handling the following commands
+   (and responding to them appropriately):
+
+   ======== ===================================================================
+   Command  Action taken
+   ======== ===================================================================
+   HELO     Accepts the greeting from the client and stores it in
+            :attr:`seen_greeting`.
+   NOOP     Takes no action.
+   QUIT     Closes the connection cleanly.
+   MAIL     Accepts the "MAIL FROM:" syntax and stores the supplied address as
+            :attr:`mailfrom`.
+   RCPT     Accepts the "RCPT TO:" syntax and stores the supplied addresses in
+            the :attr:`rcpttos` list.
+   RSET     Resets the :attr:`mailfrom`, :attr:`rcpttos`, and
+            :attr:`received_data`, but not the greeting.
+   DATA     Sets the internal state to :attr:`DATA` and stores remaining lines
+            from the client in :attr:`received_data` until the terminator
+            "\r\n.\r\n" is received.
+   ======== ===================================================================
\ No newline at end of file