Sé un Pythonista: Recibe trucos Python y accede a nuestro espacio de Slack

Tutorial Flask – Lección 14: Enviar emails con Flask

Lección 14 Enviar emails con Flask
Share on facebook
Share on twitter
Share on linkedin

Que pocas lecciones nos quedan ya para terminar el tutorial de Flask. Mientras escribo estas líneas me está dando un poco de pena, pero a la vez estoy contento por todo el trabajo realizado con el tutorial y vuestros comentarios de felicitación. En fin, el blog no para y seguiré escribiendo sobre Flask y Python. Pero como te comenté en la lección anterior, en estas últimas lecciones estoy compartiendo contigo una serie de trucos y tips interesantes. Precisamente, en esta lección vamos a descubrir cómo enviar emails con Flask.

Aunque en un principio pueda parecer que el envío de correos electrónicos es una cosa complicada, nada más lejos de la realidad. Es sencillísimo. Ya lo verás.

Si andas un poco despistad@, comentarte que esta lección continúa por donde lo dejamos en la anterior, en la que vimos cómo paginar consultas de base de datos. Puedes descargar el código correspondiente a la misma como te indico a continuación:

‼️ ATENCIÓN ‼️

🎯 Puedes descargar el código correspondiente a la Lección 13 desde el siguiente repositorio de Github:

git clone https://github.com/j2logo/tutorial-flask.git
git checkout tags/leccion13 -b leccion13

Índice

Aquí te dejo los puntos principales de esta lección:

Cómo enviar emails en Flask con Flask-Mail

Esta lección es muy corta. Ya verás como en unos pocos pasos estás enviando emails en Flask de manera muy sencilla.

Lo mejor para enviar emails con Flask es utilizar la extensión Flask-Mail. Sí, otra vez hacemos uso de una extensión para facilitarnos la vida.

La comunidad de Flask es muy activa y puedes encontrar extensiones para casi todo.

Para instalar Flask-Mail accede a un terminal, activa tu entorno virtual Python del proyecto y ejecuta lo siguiente:

$> pip install flask-mail

Configurar Flask-Mail para enviar emails en Flask

Una vez que hemos instalado Flask-Mail, debemos crear un objeto de tipo Mail al que tengamos acceso desde el resto del código. Esta clase es la responsable de enviar los mensajes, utilizando para ello los parámetros de configuración de nuestro servidor smtp de correo.

Como con otras extensiones, el objeto Mail lo crearemos e inicializaremos en el fichero app/__init__.py. A continuación, te muestro un extracto de este fichero, enseñándote solo las partes relacionadas con Flask-Mail:

from flask_mail import Mail  # 1. Importamos la clase Mail

# Resto de imports
...

...
migrate = Migrate()
mail = Mail()  # 2. Instanciamos un objeto de tipo Mail


def create_app(settings_module):
    app = Flask(__name__, instance_relative_config=True)
    
    # Inicialización de la app
    ...

    ...
    db.init_app(app)
    migrate.init_app(app, db)
    mail.init_app(app)  # 3. Inicializamos el objeto mail

    ...

Como te decía, para que el objeto Mail pueda enviar mensajes necesita conectarse a un servidor smtp de nuestra propiedad. Para ello, definiremos los siguientes parámetros de configuración en el fichero config/default.py:

MAIL_SERVERNombre de tu host smtp (Por ej: mail.smtp.com)
MAIL_PORTPuerto de tu host smtp
MAIL_USERNAMENombre de usuario del servidor smtp
MAIL_PASSWORDContraseña del usuario del servidor smtp
MAIL_USE_TLSFlag que indica si enviar los emails usando el protocolo TLS

🤔 Casualmente son los mismos parámetros que usamos para enviar emails al administrador cuando se registraba un mensaje de error en la aplicación… ¿Casualidad? Jajaja, no. Sabiendo que íbamos a usar esta extensión, aproveché para pasar los mismos parámetros en aquella ocasión al objeto SMTPHandler.

Por si no leíste esa lección, añade los parámetros al fichero config/default.py con los datos de tu servidor smtp:

# Configuración del email
MAIL_SERVER = 'tu servidor smtp'
MAIL_PORT = 587
MAIL_USERNAME = 'tu correo'
MAIL_PASSWORD = 'tu contraseña'
DONT_REPLY_FROM_EMAIL = '(Juanjo, juanjo@j2logo.com)'
ADMINS = ('juanjo@j2logo.com', )
MAIL_USE_TLS = True

❗️¡ATENCIÓN! La única pega que le encuentro a la extensión Flask-Mail es que, en principio, solo se puede configurar una cuenta smtp. No obstante, esto es más que suficiente para la mayoría de aplicaciones. Sin embargo, utilizando una misma cuenta, sí que se pueden enviar emails desde diferentes direcciones de correo.

Cómo crear un mensaje

Una vez que hemos configurado todo, ya podemos enviar emails de forma muy sencilla.

Los pasos a seguir son crear un objeto Message y llamar al método send() del objeto mail, pasando el mensaje como parámetro.

Para crear un mensaje, necesitamos indicar el asunto, la dirección de correo del emisor y las direcciones de correo a las que enviar el mensaje (como una lista):

from flask_mail import Message

msg = Message("Hola",
              sender="from@example.com",
              recipients=["to@example.com"])

También podemos especificar el nombre del emisor, pasando el nombre y la dirección de correo en una tupla. Así lo indiqué en el parámetro DONT_REPLY_FROM_EMAIL de la sección anterior:

msg = Message("Hola",
              sender=("Juanjo", "juanjo@j2logo.com"))

El contenido del mensaje lo indicamos en el atributo body, aunque también podemos crear un mensaje formateado empleando el lenguaje HTML:

msg.body = 'Bienvenid@ a j2logo'
msg.html = '<p>Bienvenid@ a <strong>j2logo</strong></p>'

Como te decía, para enviar el mensaje simplemente hay que llamar al método send() del objeto mail:

from flask_mail import Message

from app import mail

msg = Message("Hola",
              sender="from@example.com",
              recipients=["to@example.com"])

msg.body = 'Bienvenid@ a j2logo'
msg.html = '<p>Bienvenid@ a <strong>j2logo</strong></p>'

mail.send(msg)

Pues ya sabes todo lo que necesitas para enviar emails en Flask de manera sencilla. De todas formas, no te pierdas la siguiente sección en la que te voy a enseñar un último truco.

Enviar emails de forma asíncrona

El problema de enviar mensajes del modo que te he mostrado previamente, es que el envío se realiza de forma síncrona, en el mismo hilo en el que se procesa la petición web. Yo te voy a enseñar un pequeño truco para que se ejecute en un hilo diferente, de manera que el envío del email no bloquee el flujo de la petición.

Crea un nuevo paquete (directorio con un fichero __init__.py) llamado common dentro de la carpeta app. En él, crea un fichero llamado mail.py:

+ app
  |_ ...
  |_+ common
      |_ __init__.py
      |_ mail.py

Ahora pega el siguiente código en el fichero mail.py:

import logging

from smtplib import SMTPException
from threading import Thread

from flask import current_app
from flask_mail import Message

from app import mail

logger = logging.getLogger(__name__)


def _send_async_email(app, msg):
    with app.app_context():
        try:
            mail.send(msg)
        except SMTPException:
            logger.exception("Ocurrió un error al enviar el email")


def send_email(subject, sender, recipients, text_body,
               cc=None, bcc=None, html_body=None):
    msg = Message(subject, sender=sender, recipients=recipients, cc=cc, bcc=bcc)
    msg.body = text_body
    if html_body:
        msg.html = html_body
    Thread(target=_send_async_email, args=(current_app._get_current_object(), msg)).start()

Como ves, en el fichero hay dos funciones: send_email() y una función privada llamada _send_async_email().

Como usuario, desde tu código cliente solo tienes que llamar a la primera. Esta se encarga de crear un mensaje a partir de los parámetros que recibe la función y de llamar a la función _send_async_email() para que se ejecute en un nuevo hilo. Realmente, el envío del mensaje se realiza en esta última.

Probando el envío de emails desde el miniblog

Pues para finalizar esta lección tan solo nos falta probar todo lo anterior. Para ello, vamos a enviar un email de bienvenida a un usuario cuando se registra.

Abre el fichero app/auth/routes.py y actualiza la vista show_signup_form() como te indico a continuación:

from flask import (render_template, redirect, url_for,
                   request, current_app)
...
from app.common.mail import send_email
# Resto de imports
...

@auth_bp.route("/signup/", methods=["GET", "POST"])
def show_signup_form():
    ...
    if form.validate_on_submit():
        ...
        else:
            # Creamos el usuario y lo guardamos
            ...
            # Enviamos un email de bienvenida
            send_email(subject='Bienvenid@ al miniblog',
                       sender=current_app.config['DONT_REPLY_FROM_EMAIL'],
                       recipients=[email, ],
                       text_body=f'Hola {name}, bienvenid@ al miniblog de Flask',
                       html_body=f'<p>Hola <strong>{name}</strong>, bienvenid@ al miniblog de Flask</p>')
            # Dejamos al usuario logueado
            ...

Ahora, cuando se registre un nuevo usuario, recibirá un email similar al siguiente:

Enviar emails en Flask bandeja entrada
Enviar emails en Flask contenido del mensaje

Conclusión

Como habrás podido comprobar, enviar emails en Flask es muy sencillo usando la extensión Flask-Mail. Te dejo ahora para que sigas probando las distintas opciones de la extensión y mejorando el mensaje de bienvenida.

Como siempre, si tienes alguna duda puedes ponerte en contacto conmigo dejándome un mensaje al final del post, a través de mis redes sociales o enviándome un email. Estaré encantado de poder ayudarte.

‼️ ATENCIÓN ‼️

🎯 Puedes descargar el código correspondiente a la Lección 14 desde el siguiente repositorio de Github:

git clone https://github.com/j2logo/tutorial-flask.git
git checkout tags/leccion14 -b leccion14

En el siguiente tutorial veremos cómo trabajar con fechas en Flask. Para ello, mostraremos en el blog la fecha de creación de los posts y la fecha en que se envían los comentarios. ¡Te espero!

Si te ha resultado útil, compártelo con tus amigos 🤗

Share on facebook
Facebook
Share on twitter
Twitter
Share on linkedin
LinkedIn

Sé un Pythonista: Recibe trucos Python y accede a nuestro espacio de Slack

También te puede interesar

* Te informo de que los datos de carácter personal que proporciones al comentar serán tratados por Juan José Lozano Gómez como responsable de esta web. La Finalidad es moderar los comentarios. La Legitimación es gracias a tu consentimiento. Destinatarios: tus datos se encuentran alojados en Disqus (disqus.com), mi sistema de comentarios, que está acogido al acuerdo de seguridad EU-US Privacy. Podrás ejercer Tus Derechos de Acceso, Rectificación, Limitación o Suprimir tus datos enviando un email a juanjo@j2logo.com. Encontrarás más información en la POLÍTICA DE PRIVACIDAD.

Sobre j2logo

Quiero ayudarte a que seas mejor programador/a, pero no uno cualquiera, sino uno de los top.

Últimos posts

¿Quieres ser un auténtico Pythonista? 🐍

📩 Recibe de vez en cuando trucos, scripts y tutoriales Python en español para dominar el lenguaje. No es SPAM. Date de baja cuando quieras

🥇 Accede a nuestra comunidad privada de Slack: Pythonistas-es

* Al enviar el formulario confirmas que aceptas la POLITICA DE PRIVACIDAD

Pythonistas-es

SÉ UN AUTÉNTICO PYTHONISTA

📩 Recibe trucos, scripts y tutoriales Python

🥇 Accede a nuestra comunidad privada de Slack