# rm-rf.es

SMTP Server en Python con un solo comando

Hace ya unos años publiqué una entrada muy útil en la que veíamos la forma de levantar un servidor web con Python ejecutando un comando muy simple:

$ python -m SimpleHTTPServer
Serving HTTP on 0.0.0.0 port 8000 ...

Podemos hacer algo similar con un servidor SMTP. El módulo de Python SMTPServer permite lanzar con un único comando y ciertos argumentos un servidor SMTP que podemos utilizar a modo de SMTP falso para hacer pruebas o como SMTP relay completamente funcional. Lo que no he conseguido (que no se si se puede) es hacerlo funcionar como SMTP server independiente, sin necesidad de enviar los correos a través de un relay.

Para levantar un SMTP server que hace relay a otro servidor SMTP ejecutamos el siguiente comando:

$ python -m smtpd -n <HOST_SMTP>:<PUERTO_SMTP> <RELAY_SMTP>:<PUERTO_RELAY_SMTP>

Ejemplo:

$ python -m smtpd -n localhost:1125 smtp-relay:25

A partir de este momento podemos conectarnos a nuestro SMTP local y enviar mensajes haciendo relay contra smtprelay:

$ telnet localhost 1125
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 lab01 Python SMTP proxy version 0.2
mail from: test@foo.com
250 Ok
rcpt to: test@bar.com
250 Ok
data
Subject: Correo de prueba

Esto es una prueba
.
250 Ok
quit

La otra opción que os comentaba es la de crear un servidor SMTP falso. Esto nos sirve entre otras cosas para poder probar que el envío de correos de una aplicación está funcionando sin tener que enviar realmente el correo.

Tenemos que pasar el parámetro «DebuggingServer«. Esto hace que los correos que enviemos a través de nuestro SMTP simplemente se muestren en la salida estándar (cuerpo y cabeceras simples del correo):

Levantamos el SMTP:

$ python -m smtpd -n -c DebuggingServer localhost:1125

Enviamos el correo:

$ telnet localhost 1125
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 lab01 Python SMTP proxy version 0.2
mail from: test@foo.com
250 Ok
rcpt to: test@bar.com
250 Ok
data
Subject: Correo de prueba

Esto es una prueba
.
250 Ok
quit

Y vemos en STDOUT lo siguiente:

---------- MESSAGE FOLLOWS ----------
Subject: Correo de prueba
Esto es una prueba
X-Peer: 127.0.0.1

------------ END MESSAGE ------------

Lo dicho, pensaba que ejecutando del siguiente modo el comando podríamos enviar sin necesidad de relay, pero haciendo un strace al proceso veo que lo intenta enviar por defecto al relay de localhost:25 así que no debe estar implementado:

$ python -m smtpd -n localhost:1125
read(5, "127.0.0.1\tlocalhost\n127.0.1.1\tno"..., 4096) = 4096
read(5, "", 4096)                       = 0
close(5)                                = 0
munmap(0x7f20a4311000, 4096)            = 0
socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 5
connect(5, {sa_family=AF_INET, sin_port=htons(25), 
sin_addr=inet_addr("127.0.0.1")}, 16) = -1 ECONNREFUSED (Connection refused)
Salir de la versión móvil