Enviar y recibir correos electrónicos en el marco Flask de Python
La mayoría de estos tutoriales no escatimarán esfuerzos. para presentar cómo utilizar una base de datos. Hoy dejaremos de lado las bases de datos y nos centraremos en otra característica importante de las aplicaciones web: cómo enviar correos electrónicos a los usuarios.
En algunas aplicaciones ligeras, podemos agregar una función de servicio de correo electrónico que envía un correo electrónico para notificar a los usuarios cuando tienen nuevos seguidores. Hay muchas formas de implementar esta funcionalidad y queríamos proporcionar un marco general reutilizable para manejarla.
Presentamos Flask-Mail
Afortunadamente, ya tenemos muchos complementos externos para manejar el correo, que no son 100% lo que queremos, pero se acercan bastante.
Instalar Flask-Mail en un entorno virtual es muy sencillo. Los usuarios que no sean sistemas Windows pueden utilizar el siguiente comando para instalar:
1
flask/bin. /pip install flask-mail
La instalación es ligeramente diferente para los usuarios de Windows. Dado que algunos módulos utilizados por Flask-Mail ya no se ejecutan en Windows, puede utilizar los siguientes comandos:
1
flaskScriptspip install --no-deps lamson chardet flask-mail p>
Configuración:
Recuerde el ejemplo en la sección de pruebas unitarias del artículo anterior, agregamos configuración para admitir una función que nos permite recibir notificaciones por correo electrónico cuando su aplicación prueba errores. . Este ejemplo muestra cómo configurar el uso del soporte por correo electrónico.
Nuevamente, necesitamos configurar dos cosas:
Información del servidor de correo electrónico
Dirección de correo electrónico del usuario
Lo siguiente es exactamente igual como la anterior Configuración utilizada en la sección
# Email Server
MAIL_SERVER =
MAIL_PORT = 25
MAIL_USE_TLS = False
MAIL_USE_SSL = False
MAIL_USERNAME = usted
MAIL_PASSWORD = usted-contraseña
# lista de administradores
ADMINS = [usted @example .com]
No se ha configurado ningún servidor de correo o buzón de correo utilizable.
Ahora veamos un ejemplo de cómo enviar correos electrónicos usando una cuenta de Gmail:
# Servidor de correo electrónico
MAIL_SERVER =
MAIL_PORT = 465
MAIL_USE_TLS = False
MAIL_USE_ SSL = True
MAIL_USERNAME = tu-nombre-de-usuario-de-gmail
MAIL_PASSWORD = tu-contraseña-de-gmail
# lista de administradores
ADMINS = [ tu-nombre-de-usuario-gmail@gmail.com]
Además, también podemos inicializar el objeto Mail para conectarnos al servidor de correo SMTP y enviar correo:
1
2
desde flask.ext.mail importar correo
correo = Correo(aplicación)
¡Intenta enviar un correo electrónico!
Para entender cómo funciona flask mail, podemos enviar un correo electrónico desde la línea de comandos. Vaya al shell de Python y ejecute el siguiente script:
7
mensaje de flask.ext.mail
desde el correo de importación de aplicaciones
desde configuración importar ADMINS
msg = Mensaje(asunto de prueba, remitente = ADMINS[0], destinatarios = ADMINS)
msg.body = cuerpo de texto
msg.html = bHTML / b body
mail.send( msg)
El código anterior envía correos electrónicos a todos los buzones según la lista de buzones configurada en config.py, con el primer buzón como remitente. . El contenido del correo electrónico se mostrará en formato texto y html, dependiendo del formato que vea su cliente de correo electrónico.
¡Qué sencillo y compacto! Puede integrarlo en su aplicación al instante.
Mail Framework
Ahora podemos escribir una función auxiliar para enviar correos electrónicos. Esta es una versión genérica de una de las pruebas anteriores.
body = text_body
msg.
Alertas de seguidores
Ahora que tenemos el marco básico para enviar correos electrónicos, podemos escribir la función que envía alertas de seguidores (fileapp /emails.py):
11
desde flask importar render_template
desde configuración importar ADMINISTRADORES
def follower_notification( seguido, seguidor):
enviar_email([microblog] s ahora te está siguiendo! seguidor.nickname,
ADMINS[0],
[seguido .email ],
render_template(follower_email.txt,
usuario = seguido, seguidor = seguidor),
render_template(follower_email.html,
usuario = seguido, seguidor = seguidor))
¿Encontraste alguna sorpresa aquí? Nuestra vieja amiga función render_template aparece nuevamente.
Si recuerdas, usamos esta función para renderizar la plantilla en la vista. Así como no es recomendable escribir HTML en una vista, lo ideal es usar plantillas de correo electrónico. Queremos separar la lógica de la presentación tanto como sea posible, por lo que la plantilla de correo electrónico también se colocará en la carpeta de plantillas junto con otras plantillas probadas.
Por lo tanto, necesitamos escribir plantillas de correo electrónico en versión web y en texto plano para los correos electrónicos de recordatorio de los seguidores. La siguiente es la versión de texto plano (fileapp/templates/follower_email.txt):
7
8
9
Estimado. {{ usuario.nickname}},
{{follower.nickname}} ahora es seguidor.
Haga clic en el siguiente enlace para visitar la página de perfil de {{follower.nickname}}:
{{url_for(user,nick = follower.nickname, _external = True)}}
Saludos, p>
El administrador del microblog
La siguiente es la versión web del correo electrónico, que es mejor (fileapp/templates/follower_email.html):
11
12
13
pera {{user.nickname}}, /p
pa href={{url_for(usuario, apodo = seguidor. apodo, _external = True)}}{{follower.nickname}}/a ahora es un seguidor./p
table
tr valign=top
tdimg src ={ {follower.avatar(50)}}/td
td
a href={{url_for(usuario, apodo = seguidor.apodo, _externo = Verdadero)} }{{follower .nickname}}/ abr /
{{follower.about_me}}
/td
/tr
/table p>
pSaludos,/p
pThe codemicroblog/code admin
Nota: El significado del parámetro _external = True de la función url_for en la plantilla. De forma predeterminada, la función url_for genera URL relativas al nombre de dominio. Por ejemplo, la función url_for(index) devuelve /index, pero lo que queremos es enviar un correo electrónico
El último paso es manejar el flujo "seguir", que es la función de visualización que activa la alerta por correo electrónico. (fileapp/views.py):
7
8
9
desde correos electrónicos importe follower_notification
@app.route( /seguir/apodo)
@login_required
def seguir(apodo):
usuario = Usuario.query.filter_by(apodo = apodo ).first()
# ...
follower_notification(usuario, g.user)
devolver redirección(url_for(usuario, apodo = apodo))
Ahora puedes crear dos usuarios (si aún no tienes uno) y probar los nuevos usuarios haciendo que un usuario siga al otro para ver cómo funcionan las alertas por correo electrónico.
¿Eso es todo? ¿Hemos terminado ya?
Es posible que estemos entusiasmados de completar el trabajo y eliminar la alerta por correo electrónico de la lista inacabada.
Pero si pruebas la aplicación ahora, notarás que cuando haces clic en el enlace de seguimiento, la página tarda entre 2 y 3 segundos en responder y el navegador en actualizarse, algo que antes no existía.
¿Qué pasó?
El problema es que Flask-Mail utiliza el modo sincrónico para enviar correos electrónicos. El servidor web está bloqueado todo el tiempo, desde que se envía el correo electrónico hasta que se entrega y hasta que el navegador envía una respuesta. ¿Te imaginas lo que pasaría si intentáramos enviar un correo electrónico a un servidor lento o, peor aún, temporalmente fuera de línea? Esto es malo.
Esta es una limitación terrible, el envío de correos electrónicos debe ser una tarea en segundo plano y no debe interferir con el servidor web, veamos cómo solucionar este problema.
Ejecutar llamadas asincrónicas en Python
Queremos que la función send_email regrese inmediatamente después de enviar el correo electrónico, y necesitamos mover send_email a un proceso en segundo plano para la ejecución asincrónica.
De hecho, Python ya proporciona soporte para tareas asincrónicas, pero en la práctica existen otras formas de implementar tareas asincrónicas, como subprocesos y módulos multiprocesamiento.
Siempre que necesitamos enviar un correo electrónico, iniciar un hilo para manejarlo ahorra recursos en lugar de iniciar un proceso completamente nuevo. Así que pongamos la llamada mail.send(msg) en otro hilo. (fileapp/emails.py):
11
desde subprocesos importar hilo
def send_async_email(msg):
mail.send (msg)
def send_ email(asunto, remitente, destinatarios, text_body, html_body):
msg = Mensaje(asunto, remitente = remitente, destinatarios = destinatarios)
msg.body = text_body
msg.html = html_body
thr = threading.Thread(target = send_async_email, args = [msg])
thr.start()
Si pruebas la función "seguir", verás que el navegador se actualiza antes de enviar el correo electrónico.
Entonces, hemos implementado el envío asincrónico, pero si necesitamos funcionalidad asincrónica en otro lugar en el futuro, ¿necesitamos implementarla nuevamente?
El proceso es el mismo, lo que resulta en una duplicación de código en todos los casos, lo cual es muy malo.
Podemos utilizar decoradores para mejorar nuestro código. El código que utiliza el decorador es el siguiente:
11
from decoradores import async
@async
def send_async_email(msg):
correo.enviar(msj)