¿Cómo implementar la recuperación de contraseñas en una API con Node.js?
Implementar un sistema de recuperación de contraseñas es un elemento crucial en cualquier aplicación moderna. En esta sección, exploraremos cómo coordinar la recuperación de contraseñas usando una API construida con Node.js, Express, y la útil librería NodeMailer para el envío de correos electrónicos.
¿Cómo enviar correos para la recuperación de contraseñas?
El primer paso para la recuperación de contraseñas es configurar el envío de correos. Vamos a utilizar la librería NodeMailer, que simplifica el proceso de envío de correos en Node.js, al ofrecer servicios como envío de textos enriquecidos o incluso con adjuntos.
Instalación y configuración de NodeMailer
Para instalar NodeMailer, usa el siguiente comando en tu terminal:
npminstall nodemailer
Con NodeMailer instalado, es momento de crear un archivo base que usaremos para el envío de correos:
const nodemailer =require('nodemailer');asyncfunctionsendEmail(){// Configuración del transporte usando un servidor SMTP de pruebalet testAccount =await nodemailer.createTestAccount();let transporter = nodemailer.createTransport({host:'smtp.ethereal.email',port:587,secure:false,auth:{user: testAccount.user,pass: testAccount.pass,},});// Detalles del envío del correolet info =await transporter.sendMail({from:'"Ejemplo App" <noreply@example.com>',to:"usuario@ejemplo.com",subject:"Recuperación de contraseña",text:"Recupera tu contraseña siguiendo este enlace",html:"<b>Recupera tu contraseña siguiendo este enlace</b>",});console.log("Message sent: %s", info.messageId);console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));}sendEmail().catch(console.error);
¿Cómo hacer pruebas con servidores SMTP falsos?
NodeMailer permite el uso de servicios SMTP falsos, ideales para probar nuestro flujo sin enviar correos reales. Estos servidores, como Ethereal, proporcionan cuentas de prueba para enviar correos sintéticamente.
Configuración de un servidor SMTP de prueba
Para utilizar Ethereal, accede a ethereal.email y genera una cuenta de prueba. Con esta configuración, podrás emular un flujo de correos electrónicos sin enviar mensajes reales a usuarios.
let testAccount =await nodemailer.createTestAccount();let transporter = nodemailer.createTransport({host:'smtp.ethereal.email',port:587,secure:false,auth:{user: testAccount.user,pass: testAccount.pass,},});
¿Cómo enviar correos reales con NodeMailer y Gmail?
Si deseas pasar de un entorno de prueba a uno real, puedes usar servidores SMTP reales como el de Gmail. Para hacerlo, necesitas configurar tu cuenta de Gmail para permitir el acceso de “apps menos seguras”.
Configuración con Gmail SMTP
Asegúrate de seguir los pasos a continuación para usar Gmail como servidor SMTP:
Habilitar la autenticación de dos factores en tu cuenta de Google.
Crear una contraseña de aplicación desde la sección de seguridad de tu cuenta de Google.
Con la contraseña generada, modifique tu configuración de NodeMailer:
let transporter = nodemailer.createTransport({host:'smtp.gmail.com',port:465,secure:true,auth:{user:'tuusuario@gmail.com',pass:'tupasswordgeneradaporapp',},});
Este fragmento muestra cómo configurar NodeMailer para enviar correos reales a través de Gmail. Recuerda siempre almacenar credenciales sensibles como variables de entorno para asegurar tu aplicación.
Recomendaciones finales y buenas prácticas
Veamos algunos consejos y mejores prácticas cuando trabajas con NodeMailer y el envío de emails mediante servidores SMTP:
Seguridad: Siempre utiliza variables de entorno para almacenar credenciales sensoriales, y evita exponer contraseñas en tu código.
Pruebas locales: Aprovecha los servicios SMTP falsos para realizar pruebas sin correr riesgos de enviar correos reales.
Registro y Monitoreo: Implementa un sistema de logging para registrar claramente los detalles de los envíos de correos y detectar cualquier fallo o problema en el proceso.
Manejo de Errores: Implementa manejo de excepciones robusto para controlar errores en el envío de correos y asegurar que la aplicación pueda recuperarse de ellos.
Con estos conceptos y configuraciones, puedes implementar un sistema robusto de recuperación de contraseñas en tu aplicación. Este es solo el comienzo de un enfoque extensible para mejorar tanto la seguridad como la experiencia del usuario en tus aplicaciones.
Esto me viene genial para mi portfolio y una landingpage 🚀
No intenten robarle la cuenta de prueba al profe, jaja, estos hackers no dejan a nadie tranquilo
Les dejo el template de Nodemailer que se usa en el video:
"use strict";const nodemailer =require("nodemailer");// async..await is not allowed in global scope, must use a wrapperasyncfunctionmain(){// Generate test SMTP service account from ethereal.email// Only needed if you don't have a real mail account for testinglet testAccount =await nodemailer.createTestAccount();// create reusable transporter object using the default SMTP transportlet transporter = nodemailer.createTransport({host:"smtp.ethereal.email",port:587,secure:false,// true for 465, false for other portsauth:{user: testAccount.user,// generated ethereal userpass: testAccount.pass,// generated ethereal password},});// send mail with defined transport objectlet info =await transporter.sendMail({from:'"Fred Foo 👻" <foo@example.com>',// sender addressto:"bar@example.com, baz@example.com",// list of receiverssubject:"Hello ✔",// Subject linetext:"Hello world?",// plain text bodyhtml:"<b>Hello world?</b>",// html body});console.log("Message sent: %s", info.messageId);// Message sent: <b658f8ca-6296-ccf4-8306-87d57a0b4321@example.com>// Preview only available when sending through an Ethereal accountconsole.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));// Preview URL: https://ethereal.email/message/WaQKMgKddxQDoou...}main().catch(console.error);
Tutorial actual de configurar contraseña de aplicación
Hola! estuve sufriendo un poco al momento de conectar mi correo personal les dejo este tutorial actualizado💚 :
Conectar tu Gmail a nodemailer ! en 2024
Paso: ve a tu cuenta de Google y dirígete al panel de seguridad
Deberás activar la verificación dos pasos para que Google te habilite las contraseñas para aplicaciones :
Luego de activarla dirígete al buscador y ingresa "contraseña de aplicación"
Dale clic e ingresa un nombre de la aplicación
Por ultimo le das crear y listo ahora puedes usar tu contraseña
pts Recuerda usarlo como variable de entorno
Para hacer la recuperación de contraseñas se utilizará la librería Nodemailer, el comando de instalación es npm install nodemailer.
Nos brinda un código base:
"use strict";const nodemailer =require("nodemailer");// async..await is not allowed in global scope, must use a wrapperasyncfunctionmain(){// Generate test SMTP service account from ethereal.email// Only needed if you don't have a real mail account for testinglet testAccount =await nodemailer.createTestAccount();// create reusable transporter object using the default SMTP transportlet transporter = nodemailer.createTransport({host:"smtp.ethereal.email",port:587,secure:false,// true for 465, false for other portsauth:{user: testAccount.user,// generated ethereal userpass: testAccount.pass,// generated ethereal password},});// send mail with defined transport objectlet info =await transporter.sendMail({from:'"Fred Foo 👻" <foo@example.com>',// sender addressto:"bar@example.com, baz@example.com",// list of receiverssubject:"Hello ✔",// Subject linetext:"Hello world?",// plain text bodyhtml:"<b>Hello world?</b>",// html body});console.log("Message sent: %s", info.messageId);// Message sent: <b658f8ca-6296-ccf4-8306-87d57a0b4321@example.com>// Preview only available when sending through an Ethereal accountconsole.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));// Preview URL: https://ethereal.email/message/WaQKMgKddxQDoou...}main().catch(console.error);
La librería tiene un servidor que emula pruebas de email (testAccount), en transporter se ve por dónde se va a enviar el correo, qué servidor de smtp, se coloca la configuración del email. En un email real, se cambia el port a 465, se coloca true en secure y se cambian los datos de la propiedad auth por el email y password que se usará en la aplicación.
En info se coloca de quíen, para quién, el asunto y cuerpo del mensaje.
Para usar gmail como servidor smtp, en la opción de Cuenta → Seguridad, se crea una contraseña para aplicación (se debe tener configurada la verificación en dos pasos). Esa contraseña será únicamente para la aplicación y debe ser puesta como variable de entorno al igual que el user(email). Por ejemplo:
const nodemailer =require('nodemailer');// async..await is not allowed in global scope, must use a wrapperasyncfunctionsendMail(){// create reusable transporter object using the default SMTP transportlet transporter = nodemailer.createTransport({host:'smtp.gmail.com',secure:true,// true for 465, false for other portsport:465,auth:{user:'my_email@gmail.com',pass:'jgrcrj3tgf3knvs',},});// send mail with defined transport objectlet info =await transporter.sendMail({from:'"Platzinautas Boo 👻" <my_email@gmail.com>',// sender addressto:'your_email@gmail.com',// list of receiverssubject:'Nuevo correo de prueba',// Subject linetext:'Estoy usando Nodemailer!',// plain text bodyhtml:'<b>¡Holaaaaaaaaaa!</b>',// html body});console.log('Message sent: %s', info.messageId);// Message sent: <b658f8ca-6296-ccf4-8306-87d57a0b4321@example.com>// Preview only available when sending through an Ethereal accountconsole.log('Preview URL: %s', nodemailer.getTestMessageUrl(info));// Preview URL: https://ethereal.email/message/WaQKMgKddxQDoou...}sendMail();
Holaaa !!
Aca encontraran la documentacion de nodemailer
npm install nodemailer
Tutorial para activar APP passwords de google.
deben activar primero la autenticación en 2 pasos para que se pueda usar la opción indicada por el profesor.
📨 Clase #15: Cómo enviar emails con Node.js 15/20 📨
¿Cómo podemos hacer la recuperación de la contraseña? 🧲
Se debe tomar en cuenta el escenario de que el usuario olvide la contraseña, así que el modo que la pueda recuperar es por medio del envío de su email, si el email es válido, el sistema envía un correo con el link de recuperación.
¿Cómo se puede enviar el correo? 📮
Vamos a usar la librería ++Nodemailer++, entramos a la página, dentro podemos encontrar las diferentes opciones que podemos configurar con el envío de correos (como adjuntar archivos).
Copiamos el comando para instalarlo. Vamos a la terminal (presionar teclas Ctrl + Alt + T), se ejecuta: npm install nodemailer
Enviar correos a un servidor fake: 🃏
Copiamos el template del código base de la página ++Nodemailer++, vamos a ++VSC++, creamos un archivo llamado nodemailer.js, pegamos el código, lo modificamos y el código queda así:
//Se trae la librería nodemailerconst nodemailer =require("nodemailer");// async..await is not allowed in global scope, must use a wrapper//Función asíncrona:asyncfunctionsendMail(){//Usar ethereal: se usa el servidor smtp como pruebaconst transporter = nodemailer.createTransport({host:'smtp.ethereal.email',secure:false,// true for 465, false for other portsport:587,auth:{//Para configurar user y pass se entra a la página de https://ethereal.email/create//Aparece después de dar en "Create Account" la info de la cuena fake (varía cada vez que entras a ethereal):user:'guy.schultz@ ethereal. email',pass:'6zKTzq1trXHNQRgj45'}});// send mail with defined transport object//Configurar el transporter y ver donde se envía el correo, por cuál servidor smtplet info =await transporter.sendMail({from:'guy.schultz@ ethereal. email',// sender addressto:"guy.schultz@ ethereal. email",// list of receiverssubject:"Este es un correo",// Subject linetext:"Hi",// plain text bodyhtml:"<b>Hello</b>",// html body});console.log("Message sent: %s", info.messageId);// Message sent: <b658f8ca-6296-ccf4-8306-87d57a0b4321@ example .com>// Preview only available when sending through an Ethereal accountconsole.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));// Preview URL: https://ethereal.email/message/WaQKMgKddxQDoou...}sendMail();
Guardamos, vamos a la terminal y ejecutamos: node nodemailer.js
Después de correr debe salir un enlace de ++Ethereal++ que muestra el envío del correo a la cuenta falsa, en mi caso sale:
Si exploramos la página de ++Ethereal++ donde nos muestra la información del email y password de la cuenta fake, hay un enlace donde dice “Messages” en color azul, al entrar ahí aparece la bandeja de entrada del correo al que configuramos para enviar el mensaje:
Enviar correos a un servidor real: 🏆
Debemos configurar una cuenta de ++gmail++ al que tengamos acceso, vamos al menú de Configuración de la cuenta ++Gmail++ (dar click en la pestaña de los puntos de forma cuadricular), luego seleccionar “Account”, en el menú izquierdo seleccionar a “Seguridad”, al lado derecho aparecen las opciones, elegir donde dice “Verificación de 2 pasos”, quizás te pida contraseña de la cuenta de ++gmail++ que está configurando, al acceder correctamente la contraseña, seleccionar donde dice “App passwords” o “Contraseñas de Aplicaciones”, donde dice “Seleccionar Aplicación” colocamos: NodeApp, luego le damos al botón de ++GENERAR++, copiamos la contraseña generada.
Vamos al archivo nodemailer.js, editamos a transporter y a info con la información real de la dirección del email y la contraseña que generamos, el código queda así:
//Se trae la librería nodemailerconst nodemailer =require("nodemailer");// async..await is not allowed in global scope, must use a wrapper//Función asíncrona:asyncfunctionsendMail(){// create reusable transporter object using the default SMTP transportlet transporter = nodemailer.createTransport({host:"smtp.gmail.com",secure:true,// true for 465, false for other portsport:465,auth:{//Debe ser una cuenta real que tengamos acceso:user:'nicobytes.demo@ gmail. com',pass:'dmlikrjugujjlugl'}});// send mail with defined transport object//Configurar el transporter y ver donde se envía el correo, por cuál servidor smtplet info =await transporter.sendMail({from: nicobytes.demo@ gmail.com',// sender addressto:"nicobytes.demo@ gmail. com",// list of receiverssubject:"Este es un nuevo correo",// Subject linetext:"Hi",// plain text bodyhtml:"<b>Hello Platzinauta</b>",// html body});console.log("Message sent: %s", info.messageId);// Message sent: <b658f8ca-6296-ccf4-8306-87d57a0b4321@ example. com>// Preview only available when sending through an Ethereal accountconsole.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));// Preview URL: https://ethereal.email/message/WaQKMgKddxQDoou...}sendMail();
Guardamos, vamos a la terminal y ejecutamos: node nodemailer.js
Cuando se ejecuta exitosamente, no sale un enlace como cuando usamos ++Ethereal++, pero si sale que si se envió el correo por el message sent:
Si revisamos la bandeja entrada del correo que se configuró, debe aparecer el correo que enviamos usado en el código con el servidor smtp de ++gmail++.
Ya sé como hacer Spam :eyes:
Y como hacer recuperación de cuentas de usuarios vía Gmail
En lugar de estas classes debieron explicar como crear un refresh token
Por alguna razón que no llego a comprender obtuve este error al seguir la clase:
node:internal/process/promises:246triggerUncaughtException(err,true/* fromPromise */);^Error: self signed certificate in certificate chain
Lo solucioné agregando el siguiente código en createTransport:
tls:{rejectUnauthorized:false}
Si alguien me puede explicar por que tuve este error le agradezco :)
¡Hola!
tuve el mismo error, ¿encontraste por qué sucede?
No tengo disponible la opción de 'App passwords' en mi cuenta de Google ;(
App Passwords
Yo utilice ymail
no encontre la parte de app passwords en gmail a alguien mas le paso ?
Para los que definireron las variables de ambiente con la contraseña y el email, recordemos que debemos dentener y volver a correr nuestro backend, debido a que las variables de ambiente no poseen live reloading.
la opción de "App passwords" (minuto 7:50) ya no está disponible en gmail
También podemos usar mailtrap para checar nuestros correos en nodemailer
El mail si me llega a mi correo pero no lo veo en la bandeja principal de recibidos como en el video, tengo que ir a "Todos" para poderlo ver, a qué se debe esto ?
me da el siguiente error:
Se ha producido un error:Error: connect ETIMEDOUT95.216.108.161:587 at TCPConnectWrap.afterConnect[as oncomplete](node:net:1494:16){errno:-4039,code:'ESOCKET',syscall:'connect',address:'95.216.108.161',port:587,command:'CONN'}
el codigo es el siguiente:
const nodemailer =require("nodemailer");asyncfunctionsendMail(){try{let testAccount =await nodemailer.createTestAccount();let transporter = nodemailer.createTransport({host:"smtp.ethereal.email",secure:false,port:587,auth:{user:'augustus82@ethereal.email',pass:'AAn8P7MhF6hu8wT46M'}});let info =await transporter.sendMail({from:'augustus82@ethereal.email',to:"augustus82@ethereal.email",subject:"Hello ✔",text:"Hello world?",html:"<b>Hello world?</b>",});console.log("Message sent: %s", info.messageId);console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));}catch(error){console.error("Se ha producido un error:", error);}}sendMail();