Enviar correos con Python

Esta es la continuación de un articulo anterior donde generamos un reporte en excel, en esta entrada vamos a ver como enviamos dicho reporte por correo a una lista de destinatarios.

Necesitaremos los datos del servidor smtp para poder enviar los correos.

Sin entrar mucho en detalle, el contenido del mensaje de correo puede ser de tres tipos: texto plano, html o un archivo adjunto. En nuestro caso nos interesa enviar un html, para poder tener cierto formato y un archivo adjunto que sera el reporte que deseamos enviar.

Separamos en dos partes el programa para que sea mas sencillo de analizarlo y modificar a futuro.

Mensaje.py

Comenzaremos creando un archivo llamado Mensaje.py, contendrá la parte del mensaje en html; adicionalmente del constructor, tendrá dos métodos más: uno llamado agregarContenido() que nos permite agregar contenido dinámico y el otro getMensaje() que nos devuelve el html completo listo para enviarlo.

También contiene un atributo llamado subject , donde ira el asunto del mensaje.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Mensaje(object):

    def __init__(self,inicio,fin):

        self.subject = "Reporte semanal de descansos "+inicio+" al "+fin

        self.head = "<html><h2><b>Reporte de Periodo "+inicio+" - "+fin+"</b></h2>"
        self.body = "<p>Se adjunta los datos de la semana.</p>"
           

        self.tail = '<p>Para datos especificos por favor referirse a la pagina <a href="#">web</a>.</p></html>'

    def getMensaje(self):
        return self.head+self.body+self.tail
   

    def agregarContenido(self,data):
        self.body = self.body + data

ManejoMail.py

ManejoMail se ocupa de establecer la conexión con el servidor de correo; levantar los datos y enviar a la lista de destinatarios indicados.

Toma los parametros del servidor smtp, usuario y clave desde un archivo json llamado config.json con el siguiente formato:


1
2
3
4
5
6
7
{
    "smtp":"smtp",
    "mail":"demo@demo.com",
    "nombre":"UnserName",
    "puerto":"PortNumer",
    "password":"Password"
}

Finalmente ManejoMail tiene una lista como atributo interno llamado destinatarios, donde almacena la lista de los destinatarios que recibiran el correo.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import smtplib

from os.path import basename
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate
from email.MIMEBase import MIMEBase
from email import Encoders
from Mensaje import Mensaje

import json
import io

class ManejoMail(object):

    def __init__(self):

        self.destinatarios = []
        self.parametros = json.load(open("config.json", "r"))


    def enviarCorreo(self,mensaje,archivo):

        smtp = smtplib.SMTP(self.parametros["smtp"])
        smtp.login(self.parametros["mail"], self.parametros["password"])

        correo = MIMEMultipart()
       
        correo['Subject'] = mensaje.subject
        correo['From'] = self.parametros["mail"]
       
        texto = MIMEText(mensaje.getMensaje(), 'html')
        correo.attach(texto)

        part = MIMEBase('application', "octet-stream")
        part.set_payload(open(archivo, "rb").read())
        Encoders.encode_base64(part)

        part.add_header('Content-Disposition', 'attachment; filename="'+archivo+'"')
        correo.attach(part)

        for destino in self.destinatarios:
            print ("Enviando correo a ",destino)
            correo['To'] = destino
            smtp.sendmail(self.parametros["mail"], destino, correo.as_string())

       

        smtp.quit()

Si bien el listado de destinatarios lo almacenamos en una lista, tranquilamente podriamos leerlos desde una base de datos o de un archivo txt.

Cuestión 1: En este ejemplo y para no complicar tanto, los datos del servidor smtp y credenciales del usuario están dentro de un archivo json plano; podría ser prudente tomarlos desde una base de datos.

Cuestión 2: ManejoMail asume que siempre se va a enviar un archivo como adjunto; en caso que no sea lo que deseamos, se debe modificar las lineas donde se agrega el adjunto:


1
2
3
4
5
6
        part = MIMEBase('application', "octet-stream")
        part.set_payload(open(archivo, "rb").read())
        Encoders.encode_base64(part)

        part.add_header('Content-Disposition', 'attachment; filename="'+archivo+'"')
        correo.attach(part)

¿Como lo usamos?

Suponiendo que tenemos un archivo llamado ejemplo.xls, que deseamos enviar como adjunto y una lista con tres destinatarios, el uso seria el siguiente:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from ManejoMail import ManejoMail
from Mensaje import Mensaje

msg = Mensaje('01-06-2019','07-06-2019')
#Agregamos contenido al mensaje en formato html
msg.agregarContenido("<p>Agregamos un detalle al mensaje</p>")

#Agregamos una imagen al mensaje
msg.agregarContenido("<p><img src="http://www.gsampallo.com/blog/wp-content/uploads/2019/07/logo-gs_logo-fondo-negro.jpg" height="15%"    width="15%"></p>")

mMail = ManejoMail()

#Agregamos a la lista los destinatarios que deseamos que reciban el correo
mMail.destinatarios.append("destinatario1@demo.com")
mMail.destinatarios.append("destinatario2@demo.com")
mMail.destinatarios.append("destinatario3@demo.com")

mMail.enviarCorreo(msg,"ejemplo.xls")

Pueden encontrar el codigo completo del ejemplo en el repositorio de github:

https://github.com/gsampallo/automated_report_python

Un video de como funciona lo pueden ver acá:

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *