Integración de Envío de Correos Electrónicos con Spring Boot

Integración de Envío de Correos Electrónicos con Spring Boot

En el desarrollo de aplicaciones, es común necesitar funcionalidades para el envío de correos electrónicos, como el despacho de códigos de verificación o notificaciones a clientes. Este artículo detalla cómo configurar y utilizar Spring Boot para el envío de correos en diversos formatos: texto plano, contenido HTML con recursos estáticos, y correos con archivos adjuntos.

Configuración del Proyecto

Creación del Proyecto Spring Boot

Se inicia un proyecto Spring Boot básico. La estructura de carpetas puede simplificarse para pruebas iniciales.

Dependencias en el Archivo pom.xml

Es necesario incluir las dependencias de Spring Boot para correo y FreeMarker para el manejo de plantillas.

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-mail</artifactId>
    </dependency>
    <dependency>
        <groupId>org.freemarker</groupId>
        <artifactId>freemarker</artifactId>
        <version>2.3.28</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.22</version>
    </dependency>
</dependencies>

Configuración SMTP del Servidor de Correo

Para enviar correos, se requiere la autorización mediante un código de cliente proporcionado por el proveedor de correo (como 163 o QQ Mail). Esto implica habilitar SMTP y obtener credenciales. SMTP es el protocolo estándar para la transferencia de correos, que requiere autenticación para evitar spam.

Ajustes en el Archivo application.yml

Con el código de autorización, se configuran las propiedades de correo en el proyecto.

server:
  port: 8091
spring:
  mail:
    host: smtp.163.com
    protocol: smtp
    default-encoding: UTF-8
    username: usuario@163.com
    password: CODIGO_DE_AUTORIZACION
    test-connection: true
    properties:
      mail:
        smtp:
          auth: true
          starttls:
            enable: true
            required: true

Definición de un Objeto para Datos de Correo

Se crea una clase para encapsular la información del correo, como destinatarios, asunto y contenido.

package com.example;

import lombok.Data;

@Data
public class DetalleCorreo {
    private String destinatario;
    private String destinatariosMultiples;
    private String asunto;
    private String mensaje;
    private String rutaImagen;
    private String rutaArchivo;
    private String nombreRemitente;
    private String nombreDestinatario;
}

Plantilla HTML para Corrreos

Se define una plantilla HTML con marcadores de posición para personalizar el contenido del correo.

<html>
<head>
    <meta charset="UTF-8"/>
    <title>Notificación por Correo</title>
</head>
<body>
    <div style="font-family: Arial, sans-serif;">
        <h1>Plataforma de Envío de Correos</h1>
        <p>Estimado/a <strong>${nombreDestinatario}</strong>,</p>
        <p>Este correo fue enviado por <strong>${nombreRemitente}</strong>. Contenido:</p>
        <p><strong>${mensaje}</strong></p>
        <p>Fecha de envío: <strong>${fechaEnvio}</strong></p>
    </div>
</body>
</html>

Implementación de Métodos de Envío

Envío de Correo de Texto Plano

Utilizando la clase JavaMailSender de Spring, se envía un correo básico.

package com.example;

import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Component;

@Component
public class ServicioCorreo {

    private final JavaMailSender enviadorCorreo;
    private final String remitente;

    public ServicioCorreo(JavaMailSender enviadorCorreo, @Value("${spring.mail.username}") String remitente) {
        this.enviadorCorreo = enviadorCorreo;
        this.remitente = remitente;
    }

    public String enviarCorreoSimple(String destinatario, String asunto, String contenido) {
        try {
            SimpleMailMessage mensaje = new SimpleMailMessage();
            mensaje.setFrom(remitente);
            mensaje.setTo(destinatario);
            mensaje.setSubject(asunto);
            mensaje.setText(contenido);
            enviadorCorreo.send(mensaje);
            return "Correo de texto enviado exitosamente.";
        } catch (Exception e) {
            return "Error al enviar correo de texto.";
        }
    }
}

Envío de Correo con Archivos Adjuntos

Se extiende el método anterior para incluir archivos adjuntos mediante MimeMessage.

import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.javamail.MimeMessageHelper;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;

public String enviarCorreoConAdjuntos(String destinatario, String asunto, String contenido, String rutaArchivo, String rutaImagen, MultipartFile archivoSubido) {
    try {
        MimeMessage mensaje = enviadorCorreo.createMimeMessage();
        MimeMessageHelper asistente = new MimeMessageHelper(mensaje, true);
        asistente.setFrom(remitente);
        asistente.setTo(destinatario);
        asistente.setSubject(asunto);
        asistente.setText(contenido, true);
        
        FileSystemResource archivoAdjunto = new FileSystemResource(new File(rutaArchivo));
        asistente.addAttachment(archivoAdjunto.getFilename(), archivoAdjunto);
        
        FileSystemResource imagenAdjunta = new FileSystemResource(new File(rutaImagen));
        asistente.addAttachment(imagenAdjunta.getFilename(), imagenAdjunta);
        
        File archivoConvertido = convertirMultipartFile(archivoSubido);
        asistente.addAttachment(archivoConvertido.getName(), new FileSystemResource(archivoConvertido));
        
        enviadorCorreo.send(mensaje);
        return "Correo con adjuntos enviado.";
    } catch (MessagingException e) {
        return "Error al enviar correo con adjuntos.";
    }
}

private File convertirMultipartFile(MultipartFile multiFile) {
    // Lógica para convertir MultipartFile a File
    // Cambios en nombres de variables y estructura interna
    String nombreArchivo = multiFile.getOriginalFilename();
    String extension = nombreArchivo.substring(nombreArchivo.lastIndexOf("."));
    File archivoTemporal = File.createTempFile("temp_", extension);
    multiFile.transferTo(archivoTemporal);
    return archivoTemporal;
}

Envío de Correo con Plantilla HTML

Se emplea FreeMarker para renderizar una plantilla HTML con datos dinámicos.

import freemarker.template.Template;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public String enviarCorreoConPlantilla(String destinatario, String asunto, String contenido, String nombreRemitente, String nombreDestinatario) {
    try {
        Template plantilla = configuradorFreemarker.getConfiguration().getTemplate("plantilla.ftl");
        Map<String, Object> datos = new HashMap<>();
        datos.put("nombreRemitente", nombreRemitente);
        datos.put("nombreDestinatario", nombreDestinatario);
        datos.put("mensaje", contenido);
        datos.put("fechaEnvio", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        
        String htmlGenerado = FreeMarkerTemplateUtils.processTemplateIntoString(plantilla, datos);
        return enviarCorreoHtml(destinatario, asunto, htmlGenerado);
    } catch (Exception e) {
        return "Error al enviar correo con plantilla.";
    }
}

public String enviarCorreoHtml(String destinatario, String asunto, String contenidoHtml) {
    // Implementación similar a enviarCorreoSimple pero con formato HTML
}

Envío de Correo Complejo con Múltiples Destinatarios

Para soporte de envío a múltiples destinatarios y contenido avanzado, se utiliza la API de JavaMail directamente.

import javax.mail.*;
import javax.mail.internet.*;
import java.util.Properties;

public String enviarCorreoComplejo(String destinatarios, String asunto, String contenido, String rutaImagen, String rutaArchivo1, String rutaArchivo2) {
    try {
        Properties propiedades = new Properties();
        propiedades.put("mail.smtp.auth", "true");
        propiedades.put("mail.smtp.host", hostCorreo);
        propiedades.put("mail.user", remitente);
        propiedades.put("mail.password", contrasena);
        
        Session sesion = Session.getInstance(propiedades, new Authenticator() {
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(remitente, contrasena);
            }
        });
        
        MimeMessage mensaje = new MimeMessage(sesion);
        mensaje.setFrom(new InternetAddress(remitente));
        
        if (destinatarios != null && !destinatarios.isEmpty()) {
            String[] listaDestinatarios = destinatarios.split(",");
            InternetAddress[] direcciones = new InternetAddress[listaDestinatarios.length];
            for (int i = 0; i < listaDestinatarios.length; i++) {
                direcciones[i] = new InternetAddress(listaDestinatarios[i]);
            }
            mensaje.setRecipients(Message.RecipientType.TO, direcciones);
        }
        
        mensaje.setSubject(asunto);
        mensaje.setSentDate(new Date());
        
        // Construcción del contenido con imágenes y adjuntos
        MimeBodyPart imagen = new MimeBodyPart();
        // Configuración de imagen...
        
        MimeBodyPart texto = new MimeBodyPart();
        texto.setContent("<img src='cid:imagenId'/>" + contenido, "text/html; charset=utf-8");
        
        MimeBodyPart adjunto1 = new MimeBodyPart();
        // Configuración de adjunto...
        
        MimeMultipart multiparte = new MimeMultipart();
        multiparte.addBodyPart(imagen);
        multiparte.addBodyPart(texto);
        multiparte.addBodyPart(adjunto1);
        // Ajustes de subtipo según necesidad...
        
        mensaje.setContent(multiparte);
        Transport.send(mensaje);
        return "Correo complejo enviado.";
    } catch (MessagingException e) {
        return "Error al enviar correo complejo.";
    }
}

Estos métodos cubren escenarios comunes de envío de correos en aplicaciones Spring Boot, permitiendo personalización según requerimientos específicos.

Etiquetas: Spring Boot Java Mail SMTP Freemarker Envío de Correos

Publicado el 8-11 05:11