Envío de correos con Django



@eduardo_gpg

Número de visitas 8104

Tiempo de lectura 5 min

10 Diciembre 2020

Hola, te doy la bienvenida a este nueva serie en Pywombat de envío de correos electrónicos con Django. En esta serie, mediante vídeos y artículos, aprenderás a enviar correos electrónicos de forma profesional con nuestro framework favorito. 🤠 Aprenderás crear correos electrónicos en texto plano y con etiquetas HTML y hojas de estilo. De igual forma aprenderás a enviar los correos de forma asíncrona, ya sea para enviarlos de forma inmediata o programarlos para una fecha en especifica. ⏰

Sumado a todo esto, podrás traquear, exactamente que usuarios ya abrieron el correo y cuantas veces lo hicieron, además, por supuesto, de testear los correos de forma local. Vaya, será una sería bastante interesante, así que te invito a que te quedes. 🤯

Bien, sin más que decir, pongamos manos a la obra. 😎

Envio de correos

Para nosotros poder enviar correos electrónicos con Django, lo primero que haremos será definir, exactamente, que servidor de correos vamos a utilizar. Para este post, y asumiendo que la mayoría de nosotros contamos una cuenta activa en Gmail, haremos uso del servicio SMTP que Gmail nos ofrece Claro, tú por supuesto puedes hacer uso del servicio que tú desees, llámese mailchimp, sendinbluemail, mailgun etc.. y para ello, añadiremos un par de constantes a nuestro archivo settings.py; nuestro archivo de configuraciones. ✉ 😋

EMAIL_USE_TLS = True
EMAIL_USE_SSL = False
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = 'myaccount@gmail.com'
EMAIL_HOST_PASSWORD = 'my_super_password123'
EMAIL_PORT = 587

En mi caso, estas serían las configuraciones necesarias para poder autenticarme con los servidores SMTP de Gmail. Si al igual que yo, pretendes utilizar dicho servicio, únicamente deberás modificar los valores para las constantes EMAIL_HOST_USER y EMAIL_HOST_PASSWORD. Deberás colocar tus propias credenciales. 😋

Para la constante EMAIL_HOST_PASSWORD te aconsejo, ampliamente, no coloques tu contraseña directamente en el archivo, ya que la estarás exponiendo a todo el mundo, algo que sin duda no es muy buena idea. En este caso, al tratarse de un valor sensible, lo que podemos hacer es leer de una variable de entorno.

Para crear una variable de entorno en unix, ejecutaremos el siguiente comando.

export EMAIL_HOST_PASSWORD=my_super_password123

Y, para obtener el valor de una variable de entorno en Python, te aconsejo utilize la librería decouple.

Nuestro código pudiese quedar de la siguiente manera.

...
EMAIL_HOST_PASSWORD = config('EMAIL_HOST_PASSWORD')
...

Mucho mejor desde mi punto de vista.

Ok, ya tenemos las configuraciones necesarias.El siguiente paso será crear nuestro correo y enviarlo. 📨 El correo podemos crearlo prácticamente en cualquier parte de nuestro proyecto. Para este post lo haremos dentro de nuestro archivo views.py.

from django.conf import settings
from django.core.mail import send_mail

send_mail(
    'Título del correo',
    'Hola, este correo es enviado desde un post en PyWombat. 🐍',
    settings.EMAIL_HOST_USER,
    ['to@example.com'],
    fail_silently=False
)

Mediante la función send_mail seremos capaces de crear y envía correos electrónicos. La función recibe , de forma obligatoria, 4 argumentos.

  • Subject: El título de nuestro correo
  • Body: El cuerpo de nuestro correo. Principalmente en texto plano.
  • From: Quien envía el correo. Para este ejemplo utilizamos el mismo correo definido e nuestro archivo de configuraciones.
  • To: Un listado de destinatarios.

En caso el correo no pueda ser enviado, colocamos el parámetro fail_silently=False para que la excepción smtplib.SMTPException sea lanzada. Recuerda, en Python, los errores no deben pasar desapercibidos.

Y listo, de esta forma tan sencilla, es como podemos enviar correos electrónicos con Django. Ahora, si bien es cierto, la función send_mail nos permite crear y enviar correos, estos correo serán muy sencillos, todo su contenido será texto plano. Esto funciona para pequeñas practicas, pero para la vida real, no lo creo. 😣

Recibir un correo electrónico que únicamente posea texto y nada de imágenes o estilos, puede llegar a ser algo deprimente, y algo que muy probablemente a tus clientes no les termine de converser. Para evitar esto, lo que podemos hacer, es añadir un maquetad HTML al correo, y con esto podremos dar formato y estilo a lo que deseamos expresar, algo mucho más visual vaya. Para lograr esto haremos uso de la clase EmailMultiAlternatives. Veamos.

def create_mail(user_mail, subject, template_name, context):
    template = get_template(template_name)
    content = template.render(context)

    message = EmailMultiAlternatives(
        subject=subject,
        body='',
        from_email=settings.EMAIL_HOST_USER,
        to=[
            user_mail
        ],
        cc=[]
    )

    message.attach_alternative(content, 'text/html')
    return message

Aquí hay un par de puntos a explicar. En primera instancia he creado al función create_mail, la cual, como su nombre nos indica, nos permite crear un nuevo correo electrónico. La finalidad de esta función es poder crear la n cantidad de correos que deseemos, sin importar el destinatario, contenido, título etc... Es una función bastante flexible.

Dentro de la función, lo primero que hacemos, es obtener el template, el maquetado HTML que deseamos añadir al correo. Para ello utilizamos la función get_template. Esta función recibe como argumento la ruta del template a utilizar. Esta ruta la hemos definido mediante el parámetro template_name, dejando que sea quien llame a la función el encargado de definir que template ha enviar.

Una vez obtenido el template, el siguiente paso será renderizarlo, esto, por supuesto, mediante un contexto. El contexto nos será de mucha utilidad, ya que a través de él seremos capaces de crear correos electrónicos dinámicos, correos que sean diferentes para cada uno de nuestros usuarios.

A continuación creamos un objeto de tipo EmailMultiAlternatives, el cual será el correo per se, el correo que deseamos enviar. Definimos el título, el remitente, el destinatario (o destinatarios) e inclusive, si queremos enviar copias a no.

Ya con nuestro correo y el template, el último paso será añadir el maquetado. message.attach_alternative(content, 'text/html').

La función, como podemos observar, crear y retorna un correo a partir de los valores de entrada (mail, subject, template name y context).

Ok, toca el turno de probar todo esto. Y para ello voy a crear mi template welcome_mail.html.

<!DOCTYPE >
<html>
<head>
    <title>Welcome</title>
</head>
<body>
    <div>
        <h2>Hola {{ username }}, te damos la bienvenida a un post más</h2>
    </div>
</body>
</html>

Vamos a hacer el llamado a la función.

def sign_up(request):
    mail = create_mail(
        'eduardo78d@gmail.com',
        'Bienvenido a la plataforma 🥳',
        'welcome_mail.html',
        {
            'username': 'eduardo_gpg'
        }
    )

    email.send(fail_silently=False)

    return redirect('welcome')

Pasamos como argumento el correo del destinatario, el título del correo, el template a utilizar y el contexto para renderizar. Obtenemos el correo, y posteriormente lo enviamos, esto mediante el método send.

Perfecto, con esto, ya podemos enviar correos de forma mucho más profesional, y no únicamente en texto plano. 🍻

Ya para finalizar, me gustaría mencionar que, el enviar un correo electrónico es algo costoso en cuanto a términos computacionales, por lo tanto, lo recomendable es enviar los correos en segundo plano, esto para no afectar el performance del sitio we y la interacción con el usuario.

En esta ocasión, para no complicar tanto el tutorial, enviaremos los correos electrónicos mediante threads.

import threading

def send_welcome_mail(user):
    mail = create_mail(
        user.email,
        'Bienvenido a la plataforma 🥳',
        'welcome_mail.html',
        {
            'username': user.username
        }
    )

    email.send(fail_silently=False)

def sign_up(request):
    user = request.user

    thread = threading.Thread(target=send_welcome_mail, 
        args=(user,))
    thread.start()

    return redirect('welcome')

Con esto sin duda mejoraremos ampliamente el performance de la aplicación, evitando que el usuarios debe esperar una gran cantidad de tiempo.🤯

En otra entrega aprenderemos a integrar Celery. 😎

Conclusión

Perfecto, para este post aprendimos a enviar correos electrónicos con Django, esto de 2 formas diferentes, mediante texto plano y mediante un maquetado HTML.

Es cierto, en este tutorial no utilizamos ningún tipo de estilo (CSS), pero no te preocupes, eso ya lo estaremos explicando en una nueva entrega. Así que no te lo puedes perder. 🥳


¿El contenido te resulto de ayuda?

Para poder dejar tu opinión es necesario ser un usuario autenticado. Login

Más Tips y Ejercicios 🐍

Adquiere una subscripción PyWombat por tan solo $3 USD. al mes.

Conoce los beneficios de ser usuario premium:
Niveles desbloqueados: Ten accesos a todos los niveles de ejercicios. 🔓
Nuevo límite: Incrementa tu límite de ejercicios por semana. 🚀
Contenido único: Recibe semanalmente recursos exclusivos de Python (Videos, Artículos y Capitulos del libro PyWombat, comienza como desarrollador Python. 🐍