Saltar al contenidoPedro Farbo
Lección 15 / 2545 min

Envío de Emails

Envío de Emails

Implementaremos envío de emails transaccionales con Nodemailer.

Instalación

bash
npm install nodemailernpm install -D @types/nodemailer

Configuración

typescript
// src/config/mail.tsimport nodemailer from 'nodemailer'; const transporter = nodemailer.createTransport({  host: process.env.MAIL_HOST,  port: Number(process.env.MAIL_PORT),  secure: false,  auth: {    user: process.env.MAIL_USER,    pass: process.env.MAIL_PASS,  },}); export { transporter };

Mail Service

typescript
// src/services/mail.service.tsimport { transporter } from '../config/mail'; interface SendMailOptions {  to: string;  subject: string;  html: string;} export class MailService {  async send({ to, subject, html }: SendMailOptions) {    await transporter.sendMail({      from: '"E-commerce" <no-reply@ecommerce.com>',      to,      subject,      html,    });  }   async sendWelcome(user: { email: string; name: string }) {    await this.send({      to: user.email,      subject: 'Bienvenido!',      html: `        <h1>Hola ${user.name}!</h1>        <p>Tu cuenta ha sido creada con éxito.</p>      `,    });  }   async sendPasswordReset(email: string, token: string) {    const resetUrl = `${process.env.FRONTEND_URL}/reset-password?token=${token}`;     await this.send({      to: email,      subject: 'Restablecer contraseña',      html: `        <h1>Restablecer contraseña</h1>        <p>Haz clic en el enlace para restablecer:</p>        <a href="${resetUrl}">Restablecer contraseña</a>        <p>Este enlace expira en 1 hora.</p>      `,    });  }   async sendOrderConfirmation(order: OrderWithItems) {    const itemsList = order.items.map(item =>      `<li>${item.product.name} x${item.quantity} - $${item.price}</li>`    ).join('');     await this.send({      to: order.user.email,      subject: `Pedido #${order.id.slice(0, 8)} confirmado`,      html: `        <h1>Gracias por tu compra!</h1>        <p>Tu pedido ha sido confirmado:</p>        <ul>${itemsList}</ul>        <p><strong>Total: $${order.total}</strong></p>      `,    });  }} export const mailService = new MailService();

Templates con Handlebars

typescript
// src/config/mail-templates.tsimport Handlebars from 'handlebars';import fs from 'fs';import path from 'path'; const templatesDir = path.resolve(__dirname, '..', 'templates', 'emails'); export const compileTemplate = (templateName: string, data: object) => {  const templatePath = path.join(templatesDir, `${templateName}.hbs`);  const templateSource = fs.readFileSync(templatePath, 'utf8');  const template = Handlebars.compile(templateSource);  return template(data);}; // templates/emails/welcome.hbs// <h1>Hola {{name}}!</h1>// <p>Bienvenido a nuestra plataforma.</p>

Envío en Background

typescript
// Usando con Bull (colas)import Queue from 'bull'; const emailQueue = new Queue('email', process.env.REDIS_URL!); emailQueue.process(async (job) => {  const { type, data } = job.data;   switch (type) {    case 'welcome':      await mailService.sendWelcome(data);      break;    case 'order':      await mailService.sendOrderConfirmation(data);      break;  }}); // Agregar a la colaawait emailQueue.add({ type: 'welcome', data: { email, name } });

Resumen

  • ✅ Nodemailer configurado
  • ✅ Emails transaccionales
  • ✅ Templates HTML
  • ✅ Colas para background

Próxima clase: Cache con Redis! 🚀

¿Te gustó el contenido? ¡Tu contribución ayuda a mantener todo online y gratuito!

PIX:0737160d-e98f-4a65-8392-5dba70e7ff3e