"smtpd" --- Servidor SMTP
*************************

**Source code:** Lib/smtpd.py

======================================================================

Este módulo ofrece varias clases para implementar servidores SMTP
(correo electrónico).

Ver también:

  El paquete aiosmtpd es un reemplazo recomendado para este módulo. Se
  basa en "asyncio" y proporciona una API más sencilla. "smtpd"
  debería considerarse obsoleto.

Este módulo ofrece varias implementaciones del servidor; una es una
implementación genérica de no hace nada, pero cuyos métodos pueden ser
sobrescritos para crear una implementación concreta, mientras que las
otras dos ofrecen estrategias específicas de envío de correo.

Además, SMTPChannel puede ampliarse para implementar un comportamiento
de interacción muy específico con clientes SMTP.

El código admite **RFC 5321**, más las extensiones **RFC 1870** SIZE y
**RFC 6531** SMTPUTF8.


Objetos SMTPServer
==================

class smtpd.SMTPServer(localaddr, remoteaddr, data_size_limit=33554432, map=None, enable_SMTPUTF8=False, decode_data=False)

   Crea un nuevo objeto "SMTPServer", que se vincula a la dirección
   local *localaddr*. Tratará *remoteaddr* como un transmisor SMTP
   ascendente. Tanto *localaddr* como *remoteaddr* deben ser una tupla
   (host, port). El objeto hereda de "asyncore.dispatcher", por lo que
   se insertará en el bucle de eventos de "asyncore" en la
   instanciación.

   *data_size_limit* especifica el número máximo de bytes que se
   aceptarán en un comando "DATA". Un valor de "None" o "0" significa
   que no hay límite.

   *map* es el mapa de conectores que se utilizará para las conexiones
   (un diccionario inicialmente vacío es un valor adecuado). Si no se
   especifica, se utiliza el mapa de socket global "asyncore".

   *enable_SMTPUTF8* determina si la extensión "SMTPUTF8" (como se
   define en **RFC 6531**) debe estar habilitada. El valor
   predeterminado es "False". Cuando es "True", "SMTPUTF8" se acepta
   como parámetro para el comando "MAIL" y cuando está presente se
   pasa a "process_message()" en la lista "kwargs[‘mail_options’]" .
   *decode_data* y *enable_SMTPUTF8* no se pueden establecer en "True"
   al mismo tiempo.

   *decode_data* especifica si la porción de datos de la transacción
   SMTP debe decodificarse usando UTF-8. Cuando *decode_data* es
   "False" (el valor predeterminado), el servidor anuncia la extensión
   "8BITMIME" (**RFC 6152**), acepta el parámetro "BODY=8BITMIME" al
   comando "MAIL", y cuando está presente lo pasa a
   "process_message()" en la lista "kwargs['mail_options']".
   *decode_data* y *enable_SMTPUTF8* no se pueden establecer en "True"
   al mismo tiempo.

   process_message(peer, mailfrom, rcpttos, data, **kwargs)

      Lanza una excepción "NotImplementedError". Sobrescribe este
      método en subclases para hacer algo útil con este mensaje. Todo
      lo que se haya pasado en el constructor como *remoteaddr* estará
      disponible en el atributo "_remoteaddr". *peer* es la dirección
      del host remoto, *mailfrom* es el creador del sobre, *rcpttos*
      son los destinatarios del sobre y *data* es una cadena de
      caracteres que contiene el contenido del correo electrónico (que
      debe estar en formato **RFC 5321**).

      Si la palabra clave del constructor *decode_data* se establece
      en "True", el argumento *data* será una cadena Unicode. Si se
      establece en "False", será un objeto de bytes.

      *kwargs* es un diccionario que contiene información adicional.
      Está vacío si se proporcionó "decode_data=True" como argumento
      de inicialización; de lo contrario, contiene las siguientes
      claves:

         *mail_options*:
            una lista de todos los parámetros recibidos para el
            comando "MAIL" (los elementos son cadenas en mayúsculas;
            ejemplo: "['BODY=8BITMIME', 'SMTPUTF8']").

         *rcpt_options*:
            igual que *mail_options* pero para el comando "RCPT".
            Actualmente, no se admiten las opciones "RCPT TO", por lo
            que, por ahora, siempre será una lista vacía.

      Las implementaciones de "process_message" deben usar la firma
      "**kwargs" para aceptar argumentos por palabra clave
      arbitrarios, ya que las mejoras de características futuras
      pueden agregar claves al diccionario kwargs.

      Retorne "None" para solicitar una respuesta normal de "250 Ok";
      de lo contrario, retorne la cadena de respuesta deseada en
      formato **RFC 5321**.

   channel_class

      Sobrescriba este método en las subclases para usar una clase
      "SMTPChannel" personalizada para administrar clientes SMTP.

   Nuevo en la versión 3.4: El argumento del constructor *map*.

   Distinto en la versión 3.5: *localaddr* y *remoteaddr* ahora pueden
   contener direcciones IPv6.

   Nuevo en la versión 3.5: Los parámetros del constructor
   *decode_data* y *enable_SMTPUTF8*, y el parámetro *kwargs* para
   "process_message()" cuando *decode_data* es "False".

   Distinto en la versión 3.6: *decode_data* ahora es "False" por
   defecto.


Objetos DebuggingServer
=======================

class smtpd.DebuggingServer(localaddr, remoteaddr)

   Crea un nuevo servidor de depuración. Los argumentos son iguales
   que en "SMTPServer". Los mensajes se descartarán y se imprimirán en
   la salida estándar.


Objetos PureProxy
=================

class smtpd.PureProxy(localaddr, remoteaddr)

   Crea un nuevo servidor proxy puro. Los argumentos son iguales que
   en "SMTPServer". Todo se transmitirá a *remoteaddr*. Tenga en
   cuenta que ejecutar esto implica una buena posibilidad de
   convertirlo en un relé abierto, así que tenga cuidado.


Objetos MailmanProxy
====================

class smtpd.MailmanProxy(localaddr, remoteaddr)

   Crea un nuevo servidor proxy puro. Los argumentos son iguales que
   en "SMTPServer". Todo se transmitirá a *remoteaddr*, a menos que
   las configuraciones locales de mailman conozcan una dirección, en
   cuyo caso se manejará a través de mailman. Tenga en cuenta que
   ejecutar esto implica una buena posibilidad de convertirlo en un
   relé abierto, así que tenga cuidado.


Objetos SMTPChannel
===================

class smtpd.SMTPChannel(server, conn, addr, data_size_limit=33554432, map=None, enable_SMTPUTF8=False, decode_data=False)

   Crea un nuevo objeto "SMTPChannel" que gestiona la comunicación
   entre el servidor y un único cliente SMTP.

   *conn* y *addr* son según las variables de instancia que se
   describen a continuación.

   *data_size_limit* especifica el número máximo de bytes que se
   aceptarán en un comando "DATA". Un valor de "None" o "0" significa
   que no hay límite.

   *enable_SMTPUTF8* determina si la extensión "SMTPUTF8" (como se
   define en **RFC 6531**) debe estar habilitada. El valor
   predeterminado es "False". *decode_data* y *enable_SMTPUTF8* no se
   pueden establecer en "True" al mismo tiempo.

   Se puede especificar un diccionario en *map* para evitar el uso de
   un mapa de socket global.

   *decode_data* especifica si la porción de datos de la transacción
   SMTP debe decodificarse usando UTF-8. El valor predeterminado es
   "False". *decode_data* y *enable_SMTPUTF8* no se pueden establecer
   en "True" al mismo tiempo.

   Para utilizar una implementación SMTPChannel personalizada, debe
   anular "SMTPServer.channel_class" de su "SMTPServer".

   Distinto en la versión 3.5: Se agregaron los parámetros
   *decode_data* y *enable_SMTPUTF8*.

   Distinto en la versión 3.6: *decode_data* ahora es "False" por
   defecto.

   La clase "SMTPChannel" tiene las siguientes variables de instancia:

   smtp_server

      Contiene el "SMTPServer" que generó este canal.

   conn

      Contiene el objeto de socket que se conecta al cliente.

   addr

      Contiene la dirección del cliente, el segundo valor retornado
      por "socket.accept"

   received_lines

      Contiene una lista de las cadenas de línea (decodificadas
      mediante UTF-8) recibidas del cliente. Las líneas tienen su
      final de línea ""\r\n"" traducido a ""\n"".

   smtp_state

      Contiene el estado actual del canal. Será "COMMAND" inicialmente
      y luego "DATA" después de que el cliente envíe una línea "DATA".

   seen_greeting

      Contiene una cadena de caracteres que contiene el saludo enviado
      por el cliente en su "HELO".

   mailfrom

      Contiene una cadena de caracteres que contiene la dirección
      identificada en la línea "MAIL FROM:" del cliente.

   rcpttos

      Contiene una lista de cadenas de caracteres que contienen las
      direcciones identificadas en las líneas "RCPT TO:" del cliente.

   received_data

      Contiene una cadena de caracteres que contiene todos los datos
      enviados por el cliente durante el estado de DATA, hasta pero
      sin incluir la terminación ""\r\n.\r\n"".

   fqdn

      Contiene el nombre de dominio completo del servidor como lo
      retorna "socket.getfqdn()".

   peer

      Contiene el nombre del par del cliente como lo retorna
      "conn.getpeername()" donde "conn" es "conn".

   La clase "SMTPChannel" opera invocando métodos llamados
   "smtp_<command>" al recibir una línea de comando del cliente.
   Construidos en la clase base "SMTPChannel", son métodos para
   manejar los siguientes comandos (y responder a ellos de manera
   apropiada):

   +----------+---------------------------------------------------------------------+
   | Comando  | Acción tomada                                                       |
   |==========|=====================================================================|
   | HELO     | Acepta el saludo del cliente y lo almacena en "seen_greeting".      |
   |          | Establece el servidor en el modo de comando base.                   |
   +----------+---------------------------------------------------------------------+
   | EHLO     | Acepta el saludo del cliente y lo almacena en "seen_greeting".      |
   |          | Establece el servidor en el modo de comando extendido.              |
   +----------+---------------------------------------------------------------------+
   | NOOP     | No realiza ninguna acción.                                          |
   +----------+---------------------------------------------------------------------+
   | QUIT     | Cierra la conexión limpiamente.                                     |
   +----------+---------------------------------------------------------------------+
   | MAIL     | Acepta la sintaxis "MAIL FROM:" y almacena la dirección             |
   |          | proporcionada como "mailfrom". En el modo de comando extendido,     |
   |          | acepta el atributo **RFC 1870** SIZE y responde apropiadamente      |
   |          | según el valor de *data_size_limit*.                                |
   +----------+---------------------------------------------------------------------+
   | RCPT     | Acepta la sintaxis "RCPT TO:" y almacena las direcciones            |
   |          | proporcionadas en la lista "rcpttos".                               |
   +----------+---------------------------------------------------------------------+
   | RSET     | Restablece "mailfrom", "rcpttos" y "received_data", pero no el      |
   |          | saludo.                                                             |
   +----------+---------------------------------------------------------------------+
   | DATA     | Establece el estado interno en "DATA" y almacena las líneas         |
   |          | restantes del cliente en "received_data" hasta que se recibe el     |
   |          | terminador "”\r\n.\r\n”".                                           |
   +----------+---------------------------------------------------------------------+
   | HELP     | Retorna información mínima sobre la sintaxis del comando            |
   +----------+---------------------------------------------------------------------+
   | VRFY     | Retorna el código 252 (el servidor no sabe si la dirección es       |
   |          | válida)                                                             |
   +----------+---------------------------------------------------------------------+
   | EXPN     | Informa que el comando no está implementado.                        |
   +----------+---------------------------------------------------------------------+
