Si estás leyendo este tutorial es porque quieres enviar Emails usando Python. Explicaré paso a paso como componer mensajes y cómo establecer una conexión segura para enviar estos mensajes de forma sencilla.
Antes de empezar …
Enviar mensajes de correo a través de un Cliente de Email parece realmente sencillo, pero si descomponemos todas las tareas que necesitamos realizar para componer y enviar un mensaje, resulta un trabajo arduo conseguir que todo funcione correctamente. Ya sean mensajes simples o con adjuntos, estos se componen de complicadas estructuras de texto, creados únicamente con cadenas de texto.
Los estándares de SMTP (Simple Mail Transfer Protocol) y MIME (Multipurpose Internet Mail Extensions) serán los que definan cómo debe ser construido un mensaje de correo. Podemos comenzar a estudiar estos estándares y aprender a crearlos desde cero o podemos usar la librería Email de Python que nos ayuda a crearlos de forma sencilla.
Cómo se crean los mensajes
Para empezar necesitamos hacer uso de la Clase Email.Message
del módulo email.message
, que nos permite crear un mensaje sin contenido.
1 2 3 |
>>> from email.message import EmailMessage >>> message = EmailMessage() >>> print(message) |
Con esto hemos creado un objeto de la clase email.message.EmailMessage
. La librería Email se encarga de convertir el objeto EmailMessage de por si complejo en algo que pueda ser comprendido por un humano.
1 2 |
>> print(type(message)) <class 'email.message.EmailMessage'> |
Lo siguiente que vamos a hacer es crear dos variables, una con el remitente (sender) y otra con el receptor (recipient) del mensaje.
1 2 |
>>> sender = "yo@example.com" >>> recipient = "tu@example.com" |
El siguiente paso es usar estos valores a las claves From y To del mensaje.
1 2 |
>>> message['From'] = sender >>> message['To'] = recipient |
Sino queremos que nuestro mensaje sea clasificado como SPAM incluiremos un asunto (subject).
1 |
>>> message['Subject'] = 'Mensaje de prueba enviado por {}!'.format(sender) |
Tanto From como To son parte importante de las cabeceras del Email y contienen toda la información necesaria usada por los clientes y servidores de correo para enviar y recibir mensajes.
El método set_content()
se encarga de incluir automáticamente una serie de cabeceras (headers), que usarán clientes y servidores de correo. Entre ellas se incluyen la cabecera Content-Type y Content-Transfer-Encoding que indican a los clientes de email como interpretar los bytes del mensaje para convertirlos en cadenas de texto legibles al ser humano.
1 2 3 4 |
>>> body = """Hola, ... ... Este es un mensaje de prueba usando Python!""" >>> message.set_content(body) |
Cómo incluir documentos adjuntos
Ya sabemos que los mensajes se crean con cadenas de texto, por lo que cuando vamos a incluir un adjunto este también será codificado en formato de texto.
El estándar MIME (Multipurpose Internet Mail Extensions) es el encargado de codificar ficheros adjuntos a formato texto para que puedan ser enviados por correo.
Para que el destinatario de tu mensaje pueda comprender que hacer con el adjunto (attachment), necesitamos etiquetarlo usando un MIME type y subtype. De esta forma le indicamos el tipo de fichero que estamos enviando. Podemos consultar IANA (Internet Assigned Numbers Authority) para comprobar qué tipos MIME serán válidos.
Una vez conocemos el tipo y subtipo correcto de los ficheros que necesitamos enviar, los incluimos. En caso de no conocerlos, podemos usar la librería Python mimetypes
para que lo averigüe por nosotros. En el siguiente ejemplo el tipo es image y el subtipo png.
1 2 3 4 5 6 7 |
>>> import os.path >>> attachment_path = "/tmp/example.png" >>> attachment_filename = os.path.basename(attachment_path) >>> import mimetypes >>> mime_type, _ = mimetypes.guess_type(attachment_path) >>> print(mime_type) # image/png |
Como mime_type contiene tanto el tipo como subtipo separados por un slash (image/png), necesitamos que ambos estén por separado.
1 |
>>> mime_type, mime_subtype = mime_type.split('/', 1) |
Por último incluimos el adjunto a nuestro mensaje.
1 2 3 4 5 6 7 8 9 10 |
attachment_path = "./tmp/example.png" attachment_filename = os.path.basename(attachment_path) mime_type, _ = mimetypes.guess_type(attachment_path) mime_type, mime_subtype = mime_type.split('/', 1) with open(attachment_path, 'rb') as ap: message.add_attachment(ap.read(), maintype=mime_type, subtype=mime_subtype, filename=os.path.basename(attachment_path)) print(message) |
El mensaje será serializado como una cadena de texto incluyendo los ficheros adjuntos. El tipo MIME será «multipart/mixed» y cada parte del mensaje tendrá su propio tipo MIME. El cuerpo del mensaje seguirá siendo «text/plain» y la imagen «image/png«.
Cómo enviar los mensajes
Ya sabemos como construir mensajes usando Python, por lo que ahora aprenderemos a enviarlos.
El protocolo SMTP (simple mail transfer protocol) especifica cómo deben entregarse los mensajes de correo electrónico. Para esta tarea vamos a usar la librería de Python smtplib.
1 |
import smtplib |
Con smtplib
creamos un objeto que representa a nuestro servidor de correo electrónico y se va a encargar de manipular y enviar los mensajes hacia otros servidores.
Puede que ya tengas configurado un servidor de correo Qmail, Postfix, etc .. pero también es probable que no lo tengas. Comencemos creando el objeto y probando conectar a nuestra máquina local.
1 2 |
>>> import smtplib >>> mail_server = smtplib.SMTP('localhost') |
Si este nos devuelve un error, es que no tenemos ningún servidor SMTP configurado en nuestra máquina. Pero no pasa nada, podemos conectar usando los datos de conexión de otra cuenta de correo que dispongamos.
Primero tenemos que usar una capa segura de transporte y autenticar el servicio con un nombre de usuario y clave. Para lo primero usaremos la capa TLS (Transport Layer Security) conocida antiguamente como SSL (Secure Socket layer).
Disponemos de dos clases para poder realizar conexiones SMTP:
- La clase SMTP que realiza la conexión SMTP
- La clase SMTP SSL que realiza la conexión sobre la capa TLS/SSL.
1 |
mail_server = smtplib.SMTP_SSL('mail.tudominio.com') |
Si necesitamos comprobar los mensajes SMTP que puedan ser enviados de vuelta por nuestro módulo smtplib, podemos incluir el nivel de debug para el objeto SMTP_SSL. El valor 1 corresponde a True y el valor 2 corresponde a False.
1 |
mail_server.set_debuglevel(0) |
Una vez tenemos el email y la contraseña configurada, podemos autenticarnos con el servidor SMTP. Para ello usaremos el método login() de nuestro objeto SMTP.
Si el envío se realiza correctamente el método login retorna un código de estado y un mensaje explicando las razones de dicho estado. En caso de fallar el módulo lanzará una excepción con el código de error y su descripción. Veamos un ejemplo, donde nuestras credenciales no son válidas.
1 2 |
smtp_pass = "tu_password" mail_server.login(sender, smtp_pass) |
Para finalizar podemos enviar el mensaje usando el método send_message() y cerramos la conexión con el servidor con el método quit()
1 2 |
mail_server.send_message(message) # enviamos el mensaje mail_server.quit() |