Enviar email desde formulario en Flask usando FLASK-Mail + Gmail

enviar email desde flaskBuenas mi gente en este nuevo post aprenderemos a enviar email desde nuestro formulario de contacto; que hemos creado en el anterior. Va a ser bastante breve, pero muy entretenido seguramente!. Así que abrid vuestros editores, activar el entorno virtual y manos a la obra!!

Para este caso vamos a utilizar los servidores de Google y nuestra cuenta de Gmail. Así que necesitas una cuenta de este proveedor o bien puedes configurar la librería que vamos a utilizar con tu propio proveedor de servicio de correo; como podría también ser el clásico Hotmail.

Primero lo primero, veamos como había quedado nuestro formulario de contacto:

enviar email desde flask

error upsClaro que notas un error en el Captcha, pero es porque he eliminado las claves secretas de mi código. Porque a la hora de copiarlo y pegarlo aquí olvido quitarlo y luego podría tener problemas claro… Pero colocando las claves, funciona correctamente. Veamos como había quedado nuestro código tanto de la plantilla “contacto.html” y “contacto2.html” como de nuestro controlador “run.py“. Y recordemos también que habíamos creado dos formularios y dos formas distintas de procesarlos en sus respectivas rutas “/contacto” y “/contacto2“.

Código de “contacto.html“:

{% extends "base/base.html" %}
{%block head%}
<script src="https://www.google.com/recaptcha/api.js"></script>
{%endblock%}
{% block title %}Contacto{% endblock %}
{%block columna8 %}
<div class ="contenedor-neon-int">
  <div class = "title-neon" >
    <h3>Enviar mensaje a través del espacio</h3>
    <p class="mb-4"></p>
    <p class = "p-neon">Seguro tenemos mucho de que hablar! Puedes contactarme a través del siguiente formulario:</p>
    <br>

  </div>
  <form action = "/contacto" method = "post" class = "form-horizontal">
  
  <div class="form-group">
    
    <div class="col-sm-10 ml-auto mr-auto">
      <p>Tu Nombre:</p>
      <input type="name" name = "Nombre" class="form-control" placeholder="Nombre">
    </div>
  </div>
  <div class="form-group">
    <div class="col-sm-10 ml-auto mr-auto">
      <p>Tu Email:</p>
      <input type="email" name = "Email" class="form-control" placeholder="Email">
    </div>
  </div>
  <div class="form-group">
    <div class="col-sm-10 ml-auto mr-auto">
      <p>Tu mensaje:</p>
      <textarea name = "Mensaje" rows="5" cols="20" class="form-control" placeholder="Mensaje"></textarea>
    </div>
  </div>
  <div class="g-recaptcha" align = "center" data-sitekey="{{sitekey}}"></div>
    <div class="col-sm-10 ml-auto mr-auto">
      <br>
      <div align = "right">
      <a href="#"><button type="submit">
        <span></span>
        <span></span>
        <span></span>
        <span></span>
        ENVIAR MENSAJE!
      </button></a>
    </div>
    </div>
    <br>
  </div>
</form>
{%endblock %}
  {% block columna4 %}
  {% endblock %}

Código de “contacto2.html“:

{% extends "base/base.html" %}
{% import "bootstrap/wtf.html" as wtf %}

{%block head%}
<script src="https://www.google.com/recaptcha/api.js"></script>
{%endblock%}
{% block title %}Contacto{% endblock %}
{%block columna8 %}
<div class ="contenedor-neon-int">
  <div class = "title-neon" >
    <h3>Enviar mensaje a través del espacio</h3>
    <p class="mb-4"></p>
    <p class = "p-neon">Seguro tenemos mucho de que hablar! Puedes contactarme a través del siguiente formulario:</p>
    <br>

  </div>
<!--Aquí estaba el formulario HTML anteriormente-->
    <div class="row">
      <div class="col-sm-10 ml-auto mr-auto">
        <form action = "/contacto2" method = "post" class = "form-horizontal">
          {{ form.csrf_token() }}
        {{ wtf.form_field(form.name, class='form-control', 
           placeholder='Nombre') }}
        {{ wtf.form_field(form.email, class='form-control', 
           placeholder='Email') }}
        {{ wtf.form_field(form.message, class='form-control', 
           placeholder='Tu mensaje') }}
           {{ recaptcha }}
           <div align = "right">
            <a href="#"><button type="submit">
              <span></span>
              <span></span>
              <span></span>
              <span></span>
              Enviar!
            </button></a>
          </div></form>

      </div></div>

{%endblock %}
  {% block columna4 %}
  {% endblock %}

Código de “forms.py“:

#Importar

from flask_wtf import FlaskForm
#Aquí importamos, campodetexto, validadoresdedatos, y el boton submit
from wtforms import StringField, validators, SubmitField
#Aquí de los validadores importamos el datoobligatorio y el email
from wtforms.validators import DataRequired, Email
import email_validator

class miformulario(FlaskForm):
    name = StringField(label='Nombre', validators=[DataRequired()])
    email = StringField(label='Email', validators=[DataRequired(), Email(granular_message=True)])
    message = StringField(label='Mensaje')
    submit = SubmitField(label="Enviar")

Código de “run.py“:

#Importar
from flask import Flask, render_template, request
import requests, json #Solución import requests from venv
from forms import miformulario
from flask_bootstrap import Bootstrap #importamos Bootstrap para el formulario
from flask_recaptcha import ReCaptcha # Importar ReCaptcha

#Crear app medante instancia
app = Flask(__name__)
#Configuraciones
app.secret_key = "pythones.netelmejorblog"
Bootstrap(app) #Decoramos nuestra app con bootstrap
#Recaptcha
app.config['RECAPTCHA_SITE_KEY'] = 'captcha' 
app.config['RECAPTCHA_SECRET_KEY'] = 'captcha' 
recaptcha = ReCaptcha(app)


#Crear rutas con sus correspondientes funciones
#INICIO
@app.route('/', methods=['GET'])
def index():
    return render_template('/index.html')
#MI BLOG
@app.route('/blog', methods=['GET'])
def blog():
    return render_template('/blog.html')
#MIS PROYECTOS
@app.route('/mis-proyectos', methods=['GET'])
def mostrarproyectos():
    return render_template('mis-proyectos.html')
#MIS HABILIDADES
@app.route('/habilidades', methods=['GET'])
def habilidades():
    return render_template('mis-habilidades.html')
#CONTACTO
@app.route("/contacto", methods=["GET", "POST"])
def contacto():
    sitekey = "captcha"

    if request.method == "POST":
        name = request.form['Nombre']
        email = request.form['Email']
        Mensaje = request.form['Mensaje']
        respuesta_del_captcha = request.form['g-recaptcha-response']
        
        if comprobar_humano(respuesta_del_captcha):
           #Si devuelve True
            status = "Exito."
            print (status)
        else:
           #Si devuelve False
            status = "Error, vuelve a comprobar que no eres un robot."
            print (status)

    return render_template("contacto.html", sitekey=sitekey)


#CONTACTO2 - FLASKFORMS WTFORMS
@app.route("/contacto2", methods=["GET", "POST"])
def contacto2():
    miform = miformulario()
    if miform.validate_on_submit() and recaptcha.verify():
        print(f"Name:{miform.name.data},Email:{miform.email.data},message:{miform.message.data}")
    else:
        print("Algún dato es invalido")
    return render_template("contacto2.html", form=miform)


def comprobar_humano(respuesta_del_captcha):
    secret = "captcha"
    payload = {'response':respuesta_del_captcha, 'secret':secret}
    response = requests.post("https://www.google.com/recaptcha/api/siteverify", payload)
    response_text = json.loads(response.text)
    return response_text['success']

#Ejecutar nuestra app cuando ejecutemos este archivo run.py
if __name__ == '__main__':
    app.run(debug=True)

Instalar Flask-Mail para enviar email’s

Para enviar un mail utilizando flask vamos a usar una librería llamada Flask-Mail y la vamos a configurar de manera que podamos utilizar el servidor de Gmail. Entonces al momento que nuestro visitante complete el formulario para contactarnos se enviará una solicitud al servidor de Gmail para que nos envíe un correo a nuestra cuenta de mail personal, pero utilizando nuestra cuenta de Gmail. Puede o no ser la misma cuenta que envía y recibe el mensaje, lo bueno será que nos quedará el mail que haya completado nuestro visitante y luego podremos responderle a su casilla de correo.

En definitiva lo que intento explicar es que puedes utilizar solo una cuenta de Mail y será como enviarte un mail a ti mismo. O también puedes utilizar dos cuentas diferentes, una para enviar los correos y otra para recibirlos.

Comencemos activando nuestro entorno virtual e instalando flask-mail.

 

pip install flask-mail

Ahora como siempre, simplemente debemos importarlo en nuestro controlador “run.py“:

from flask_mail import Mail, Message

 

Configurar Flask-Mail

Normalmente en nuestro proyecto deberíamos tener un archivo de configuración donde son alojadas todas las configuraciones de nuestro proyecto. Pero como nosotros estamos empezando recientemente con FLASK lo haremos directamente en el archivo “run.py” y ya luego aprenderemos a organizar un proyecto FLASK. Así que en nuestro archivo “run.py” debemos añadir las siguientes configuraciones:

app.config['MAIL_SERVER']='smtp.gmail.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USERNAME'] = 'yourId@gmail.com'
app.config['MAIL_PASSWORD'] = '*****'
app.config['MAIL_USE_TLS'] = False
app.config['MAIL_USE_SSL'] = True
mail = Mail(app)

Estas configuraciones nos permiten definir el servidor de Mail y hacer login en el. Pero lo cierto es que para utilizar el servidor de Gmail primeramente debemos configurarlo para admitir este tipo de solicitudes de nuestra aplicación FLASK. De lo contrario nos encontraremos con algunas trabas de seguridad que Gmail tomará como medida preventiva.. Así que vamos a configurar nuestra cuenta de email en Gmail:

Configurar nuestra cuenta Gmail para admitir solicitudes externas

Aunque nuestro usuario / password de cuenta de Gmail sean validos el servidor de Gmail nos va a rechazar la sesión debido a un mecanismo de seguridad. Para ello debemos ir primero a:

https://support.google.com/accounts/answer/185839

Donde obtendremos información acerca de activar “verificación en dos pasos” que es requerida para poder activar la opción de logearse desde app’s externas a Google. Y una vez activada dicha verificación debemos establecer una contraseña para utilizar app’s externas:

Así que primero debes ir a tu Cuenta de google>Seguridad:

gmail1

 

Luego debemos hacer clic en “Contraseñas de aplicaciones” y establecer nuestra app creando automáticamente una contraseña para su acceso:

enviar email flask gmail

 

Y así Google nos otorga una “contraseña de 16 dígitos” que podemos usar en nuestra App en el apartado de configuración de Flask-Mail. Utilizarás esta contraseña y no la tradicional que utilizas para iniciar sesión en Gmail!

Aquí en StackOverflow puedes leer más acerca de este método de seguridad de google.

 

En mi caso añadí la configuración de Flask-Mail debajo de la del Google ReCaptcha; mi “run.py” quedó así:

#Importar
from flask import Flask, render_template, request
import requests, json #Solución import requests from venv
from forms import miformulario
from flask_bootstrap import Bootstrap #importamos Bootstrap para el formulario
from flask_recaptcha import ReCaptcha # Importar ReCaptcha
from flask_mail import Mail, Message

#Crear app medante instancia
app = Flask(__name__)
#Configuraciones
app.secret_key = "pythones.netelmejorblog"
Bootstrap(app) #Decoramos nuestra app con bootstrap
#Recaptcha
app.config['RECAPTCHA_SITE_KEY'] = 'captcha' 
app.config['RECAPTCHA_SECRET_KEY'] = 'captcha' 
recaptcha = ReCaptcha(app)
#Flask-Mail
app.config['MAIL_SERVER']='smtp.gmail.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USERNAME'] = 'yourId@gmail.com'
app.config['MAIL_PASSWORD'] = '*****'
app.config['MAIL_USE_TLS'] = False
app.config['MAIL_USE_SSL'] = True
mail = Mail(app) 



#Crear rutas con sus correspondientes funciones
#INICIO
@app.route('/', methods=['GET'])
def index():
    return render_template('/index.html')
#MI BLOG
@app.route('/blog', methods=['GET'])
def blog():
    return render_template('/blog.html')
#MIS PROYECTOS
@app.route('/mis-proyectos', methods=['GET'])
def mostrarproyectos():
    return render_template('mis-proyectos.html')
#MIS HABILIDADES
@app.route('/habilidades', methods=['GET'])
def habilidades():
    return render_template('mis-habilidades.html')
#CONTACTO
@app.route("/contacto", methods=["GET", "POST"])
def contacto():
    sitekey = "captcha"

    if request.method == "POST":
        name = request.form['Nombre']
        email = request.form['Email']
        Mensaje = request.form['Mensaje']
        respuesta_del_captcha = request.form['g-recaptcha-response']
        
        if comprobar_humano(respuesta_del_captcha):
           #Si devuelve True
            status = "Exito."
            print (status)
        else:
           #Si devuelve False
            status = "Error, vuelve a comprobar que no eres un robot."
            print (status)

    return render_template("contacto.html", sitekey=sitekey)


#CONTACTO2 - FLASKFORMS WTFORMS
@app.route("/contacto2", methods=["GET", "POST"])
def contacto2():
    miform = miformulario()
    if miform.validate_on_submit() and recaptcha.verify():
        print(f"Name:{miform.name.data},Email:{miform.email.data},message:{miform.message.data}")
    else:
        print("Algún dato es invalido")
    return render_template("contacto2.html", form=miform)


def comprobar_humano(respuesta_del_captcha):
    secret = "captcha"
    payload = {'response':respuesta_del_captcha, 'secret':secret}
    response = requests.post("https://www.google.com/recaptcha/api/siteverify", payload)
    response_text = json.loads(response.text)
    return response_text['success']

#Ejecutar nuestra app cuando ejecutemos este archivo run.py
if __name__ == '__main__':
    app.run(debug=True)

Ahora es momento de ingresar nuestros datos. En el caso del servidor lo dejamos como está y añadimos nuestra cuenta y nuestra contraseña que acabamos de crear.. El resto quedará igual..

Añadir el código y enviar un email de prueba

Vamos a añadir el código necesario para enviar los datos que procesamos en nuestro formulario de contacto y enviarlo a través de un correo usando el servidor y nuestra de Google o Gmail al mismo u otro correo donde quieras recibir los mails que te envíen desde la sección contacto de tu aplicación.

En mi caso solo tengo una cuenta de correo Gmail y utilizaré la misma tanto para enviar como para recibir los correos.

Podemos hacerlo de dos formas, una sería creando una función aparte y llamándola desde nuestra función de las rutas contacto. O bien podríamos hacerlo directamente desde la ruta contacto. Pero voy a elegir la primera opción, así que en nuestro archivo “run.py” donde tenemos la función “comprobar_humano” vamos a crear la función “enviar_correo” y dentro de ella instanciaremos “Message” de la librería “flask-mail” para enviar un mensaje cuyo datos pasaremos mediante el parámetro “mensaje”:

def enviar_correo(mensaje):
    pass

 

Podemos leer la documentación de Flask-Mail para tener más datos acerca de como enviar un mail con esta librería. Creamos nuestra función y añadimos lo siguiente:

def enviar_correo(mensaje):
    msg = Message(
    subject  = (f"{mensaje.get('Email')} quiere contactarse contigo desde tu app"), 
    sender = mensaje.get('Email'), 
    recipients = ['correo-donde-quieres-recibir@gmail.com'], 
    body= mensaje.get('Mensaje')
    )  
    mail.send(msg)

Explicando un poco la función nuestra variable “msg” obtendrá del parámetro que pasamos en la función “mensaje” los datos “subject”, “Email” y “Mensaje”. Y estos nombres deben coincidir con los del formulario, además de ello he añadido el parámetro “subject” que no procesamos en nuestro formulario donde obtenemos el email de nuestro emisor.

Claro que nuestro parámetro “mensaje” de nuestra función enviar_correo debe ser una lista o diccionario que contenga estos datos, los cuales imaginas serán obtenidos del formulario y los pasaremos al llamar la función “enviar_correo“.

Así que ahora es momento de configurar nuestras funciones de “contacto” para enviar el mail en ambas rutas, recuerdas que teníamos dos “contacto” y “contacto2”.

#CONTACTO
@app.route("/contacto", methods=["GET", "POST"])
def contacto():
    sitekey = "clave-secreta-del-sitio-recaptcha"

    if request.method == "POST":
        name = request.form['Nombre']
        email = request.form['Email']
        Mensaje = request.form['Mensaje']

        respuesta_del_captcha = request.form['g-recaptcha-response']
        
        if comprobar_humano(respuesta_del_captcha):
           #Si devuelve True
            status = "Exito."
            enviar_correo(request.form)
            print (status)
        else:
           #Si devuelve False
            status = "Error, vuelve a comprobar que no eres un robot."
            print (status)

    return render_template("contacto.html", sitekey=sitekey)

Lo único que tenemos que hacer es llamar a nuestra función “enviar_correo” pasando como parámetros los datos del formulario usando la función “request“. Y esto lo hacemos dentro del condicional que comprueba si nuestro Captcha era correcto, claro. NO QUEREMOS QUE NOS ENVÍEN CORREOS SIN COMPROBAR EL CAPTCHA PRIMERO, SERIA UNA VULNERABILIDAD Y ESTAS PONIENDO EN JUEGO TU CUENTA DE GMAIL.

Ahora es momento de procesar los datos y enviar el correo usando nuestra función para comprobar si todo funciona correctamente. En este caso utilizaré primero la función y ruta “contacto” y luego lo haremos con “contacto2” donde utilizamos Flask-Forms o WTForms. ¿Recuerdas?

Hagamos un test, mi “run.py” quedó así:

#Importar
from flask import Flask, render_template, request
import requests, json #Solución import requests from venv
from forms import miformulario
from flask_bootstrap import Bootstrap #importamos Bootstrap para el formulario
from flask_recaptcha import ReCaptcha # Importar ReCaptcha
from flask_mail import Mail, Message

#Crear app medante instancia
app = Flask(__name__)
#Configuraciones
app.secret_key = "pythones.netelmejorblog"
Bootstrap(app) #Decoramos nuestra app con bootstrap
#Recaptcha
app.config['RECAPTCHA_SITE_KEY'] = 'clave-del-sitio-google-recaptcha' 
app.config['RECAPTCHA_SECRET_KEY'] = 'tu-clave-secreta-recaptcha' 
recaptcha = ReCaptcha(app)
#Flask-Mail
app.config['MAIL_SERVER']='smtp.gmail.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USERNAME'] = 'tu-correo-que-va-a-enviar@gmail.com'
app.config['MAIL_PASSWORD'] = 'password-obtenido-de-google-en-el-paso-primero'
app.config['MAIL_USE_TLS'] = False
app.config['MAIL_USE_SSL'] = True
mail = Mail(app) 



#Crear rutas con sus correspondientes funciones
#INICIO
@app.route('/', methods=['GET'])
def index():
    return render_template('/index.html')
#MI BLOG
@app.route('/blog', methods=['GET'])
def blog():
    return render_template('/blog.html')
#MIS PROYECTOS
@app.route('/mis-proyectos', methods=['GET'])
def mostrarproyectos():
    return render_template('mis-proyectos.html')
#MIS HABILIDADES
@app.route('/habilidades', methods=['GET'])
def habilidades():
    return render_template('mis-habilidades.html')
#CONTACTO
@app.route("/contacto", methods=["GET", "POST"])
def contacto():
    sitekey = "clave-del-sitio-google-recaptcha"

    if request.method == "POST":
        name = request.form['Nombre']
        email = request.form['Email']
        Mensaje = request.form['Mensaje']

        respuesta_del_captcha = request.form['g-recaptcha-response']
        
        if comprobar_humano(respuesta_del_captcha):
           #Si devuelve True
            status = "Exito."
            enviar_correo(request.form)
            print (status)
        else:
           #Si devuelve False
            status = "Error, vuelve a comprobar que no eres un robot."
            print (status)

    return render_template("contacto.html", sitekey=sitekey)


#CONTACTO2 - FLASKFORMS WTFORMS
@app.route("/contacto2", methods=["GET", "POST"])
def contacto2():
    miform = miformulario()
    if miform.validate_on_submit() and recaptcha.verify():
        print(f"Name:{miform.name.data},Email:{miform.email.data},Mensaje:{miform.message.data}")
    else:
        print("Algún dato es invalido")
    return render_template("contacto2.html", form=miform)


def comprobar_humano(respuesta_del_captcha):
    secret = "tu-clave-secreta-recaptcha"
    payload = {'response':respuesta_del_captcha, 'secret':secret}
    response = requests.post("https://www.google.com/recaptcha/api/siteverify", payload)
    response_text = json.loads(response.text)
    return response_text['success']

def enviar_correo(mensaje):
    msg = Message(
    subject  = (f"{mensaje.get('Email')} quiere contactarse contigo desde tu app"), 
    sender = mensaje.get('Email'), 
    recipients = ['correo-donde-quieres-recibir@gmail.com'], 
    body= mensaje.get('Mensaje')
    )  
    mail.send(msg)

#Ejecutar nuestra app cuando ejecutemos este archivo run.py
if __name__ == '__main__':
    app.run(debug=True)

 

Probando enviar un email desde nuestro formulario HTML

Por supuesto tu debes reemplazar algunos datos. Desde los de tu correo a los del ReCaptcha. Ahora fíjate:

 

Y Voilaa!. Se hizo la magia!

Ahora veamos como lo haríamos con la ruta “contacto2” donde aprendimos a usar WTForms.

 

Enviar un email desde formulario creado con WTForms o Flask-Forms

Recordemos que nuestra función creada para el formulario usando WTForms era mucho más corta y sencilla, de hecho comprobamos todos los datos en un único condicional que comprueba que estén ingresado los datos requeridos por el formulario a la vez que también comprueba que el ReCaptcha sea correcto:

#CONTACTO2 - FLASKFORMS WTFORMS
@app.route("/contacto2", methods=["GET", "POST"])
def contacto2():
    miform = miformulario()
    if miform.validate_on_submit() and recaptcha.verify():
        print(f"Name:{miform.name.data},Email:{miform.email.data},Mensaje:{miform.message.data}")
    else:
        print("Algún dato es invalido")
    return render_template("contacto2.html", form=miform)

En el caso de utilizar WTForms nos encontraremos un poco más complicados para utilizar la misma función “enviar_correo“, ya que si solamente llamáramos a la función pasando como parámetro los datos de “miform” obtendríamos diversos errores. Pero como sabemos la librería Flask-Mail admite como parámetro un diccionario que contiene los datos del mensaje y entre ellos los del emisor (sender), receptor, sujeto, etc.

Y en nuestra función “enviar_correo” trabajamos con el método “get“, ¿Lo recuerdas?. Hablo de .get(), ojo!!. No de método de solicitud GET heee!

Lo aprendimos cuando trabajamos con diccionarios y más te vale lo recuerdes!. Fíjate aquí: Métodos de diccionarios en Python

Así que simplemente debemos pasar los datos como un diccionario nuevo y colocar el mismo nombre de las claves que nuestra función enviar_correo requiere cuando utiliza “get“:

Así que simplemente lo que tenemos que hacer es pasarle a nuestra función “enviar_correo” un diccionario como parámetro con algunos de los datos obtenidos de “miform“!. Que gracias a nuestro doble condicional si añadimos código dentro sabremos que ya fueron comprobados y validos los datos antes de enviar el correo. Nos bastaría añadir algo así:

#CONTACTO2 - FLASKFORMS WTFORMS
@app.route("/contacto2", methods=["GET", "POST"])
def contacto2():
    miform = miformulario()
    if miform.validate_on_submit() and recaptcha.verify():
        print(f"Name:{miform.name.data},Email:{miform.email.data},Mensaje:{miform.message.data}")
        mimensaje = {
            'Email': miform.email.data,
            'Mensaje' : miform.message.data }

        enviar_correo(mimensaje)
    else:
        print("Algún dato es invalido")
    return render_template("contacto2.html", form=miform)

¿Y por qué solo añadimos el mail y el mensaje?. Porque el resto de datos ya los tienes en la función enviar correo!

Así que solo son necesarios esos dos argumentos enviados en forma de diccionario como parámetro para nuestra función. ¿Entiendes?

Fíjate en esto:

código enviar mail con flask

Creo que se sobre entiende, que estamos pasando como parámetro un diccionario para que nuestra función tal como estaba con el método .get() obtenga los datos de las claves que son estrictamente necesarios. Ya que los demás están definidos en la misma función enviar_correo(). Y pues, esto ha sido todo veamos que funciona, claro que funciona!:

 

Probando enviar un email desde nuestro formulario Creado con WTForms o Flask-Forms

Aquí accedo mediante la ruta “/contacto2” porque recuerda que es un formulario alternativo, tu puedes usar el que prefieras.

 

flask formularios enviar mailBien hasta aquí llegamos hoy!!!.

Mis saludos y nos veremos pronto, no olvidéis compartir mi blog para llegar a mas personas interesadas en Python!

 

 

 

 

Compartir es agradecer! :)

Hey no te vayas sin dejarme un comentario!

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Aprende a programar de manera profesional!

¿Todavía sin obtener una retribución justa de tu aprendizaje?

Curso de Python Udemy

Convierteté en un verdadero Jedy de Python y comienza a desarrollar aplicaciones de forma profesional obteniendo un certificado de Udemy!. Pasate por la sección de Cursos Premium y realiza los mejores cursos con certificación válida a nivel internacional por apenas unos dolares!