Envío de Correos Electrónicos con Spring Boot y SMTP de Gmail
Este documento detalla el proceso de configuración y envío de correos electrónicos en una aplicación Spring Boot, utilizando el servidor SMTP de Gmail.
1. Habilitando el SMTP de Gmail y Generando una Contraseña de Aplicación
Para usar el SMTP de Gmail en una aplicación externa, necesitas una "Contraseña de aplicación" (App Password) si tienes la verificación en dos pasos activada. Es altamente recomendable tener la verificación en dos pasos activada para mayor seguridad.
Paso a Paso para Generar una Contraseña de Aplicación:
- Accede a tu Cuenta de Google: Ve a myaccount.google.com.
- Ve a Seguridad: En el menú lateral izquierdo, haz clic en "Seguridad".
- Verificación en dos pasos: Desplázate hacia abajo hasta la sección "Cómo accedes a Google" y haz clic en "Verificación en dos pasos". Si aún no está activada, sigue las instrucciones para activarla.
- Contraseñas de aplicaciones: Después de activar la verificación en dos pasos, vuelve a la pantalla de "Seguridad" y busca "Contraseñas de aplicaciones". Haz clic en ella.
- Generar Nueva Contraseña de Aplicación:
- Selecciona "Correo" en el menú desplegable "Seleccionar la aplicación".
- Selecciona "Otro (nombre personalizado)" en el menú desplegable "Seleccionar el dispositivo" y escribe un nombre como "Spring Boot Email" (opcional, solo para identificación).
- Haz clic en "Generar".
- Copia la Contraseña de Aplicación: Se mostrará una contraseña de 16 caracteres en un cuadro amarillo. Copia esta contraseña y guárdala en un lugar seguro. Esta será la contraseña que usarás en tu aplicación Spring Boot, y no la contraseña de tu cuenta de Google.
Observación: Si no quieres activar la verificación en dos pasos, tendrías que activar la opción "Acceso de aplicaciones poco seguras" (Less secure app access) en la configuración de seguridad de Google. Sin embargo, esta opción está descontinuada para cuentas personales desde el 30 de mayo de 2022 y no se recomienda por razones de seguridad. Siempre prefiere usar las "Contraseñas de aplicaciones".
2. Configurando el Proyecto Spring Boot
2.1. Añadir Dependencia de Spring Mail
Añade la dependencia spring-boot-starter-mail a tu archivo pom.xml.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
2.2. Configurar las Propiedades de Gmail en application.properties
En el archivo src/main/resources/application.properties añade las siguientes configuraciones:
application.properties:
# Propiedades del Servidor SMTP de Gmail
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=${EMAIL_USER} # Tu dirección de correo de Gmail en una variable de entorno
spring.mail.password=${EMAIL_SENHA} # La contraseña de aplicación generada anteriormente en una variable de entorno
# Propiedades adicionales para SMTP seguro (TLS)
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
spring.mail.properties.mail.smtp.connectiontimeout=5000
spring.mail.properties.mail.smtp.timeout=5000
spring.mail.properties.mail.smtp.writetimeout=5000
organiza tus variables de entorno
3. Creando el Servicio de Correo
Crea una clase de servicio para manejar el envío de correos electrónicos.
// src/main/java/com/example/emaildemo/service/EmailService.java
package com.example.emaildemo.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
@Service
public class EmailService {
@Autowired
private JavaMailSender mailSender;
/**
* Envía un correo simple.
* @param to El destinatario del correo.
* @param subject El asunto del correo.
* @param text El cuerpo del correo.
*/
public void sendSimpleEmail(String to, String subject, String text) {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom("tu_email@gmail.com"); // Puede ser leído de la configuración de application.properties
message.setTo(to);
message.setSubject(subject);
message.setText(text);
mailSender.send(message);
System.out.println("Correo enviado exitosamente a: " + to);
}
// Puedes añadir métodos para enviar correos con HTML, archivos adjuntos, etc.
// Ejemplo de envío de correo con HTML (requiere MimeMessageHelper)
/*
import jakarta.mail.internet.MimeMessage;
import org.springframework.mail.javamail.MimeMessageHelper;
public void sendHtmlEmail(String to, String subject, String htmlContent) {
try {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8"); // true para multipart/mixed
helper.setFrom("tu_email@gmail.com");
helper.setTo(to);
helper.setSubject(subject);
helper.setText(htmlContent, true); // true indica que el contenido es HTML
mailSender.send(message);
System.out.println("Correo HTML enviado exitosamente a: " + to);
} catch (jakarta.mail.MessagingException e) {
e.printStackTrace();
// Maneja la excepción
}
}
*/
}
ThymeLeaf: Adicionalmente, si quieres enviar correos en HTML enriquecido, puedes usar un motor de plantillas como Thymeleaf.
5. Consideraciones Importantes y Mejores Prácticas
- Seguridad de las Credenciales:
- Nunca coloques credenciales directamente en el código fuente en un entorno de producción.
- Para entornos de producción, utiliza variables de entorno, Spring Cloud Config, HashiCorp Vault u otros servicios de gestión de secretos para inyectar las credenciales.
- Si estás usando Docker, puedes usar secretos de Docker.
- Manejo de Excepciones: Implementa un manejo de excepciones robusto para lidiar con fallos en el envío de correos (ej: red, autenticación, etc.).
- Logs: Configura logs para registrar el estado del envío de correos, incluyendo éxitos y fallos, para fines de depuración y auditoría.
- Procesamiento Asíncrono: Para evitar bloquear el hilo principal de tu aplicación (especialmente en solicitudes web), considera enviar correos de forma asíncrona usando
@Asyncy@EnableAsyncen tu clase de configuración principal.- Añade
@EnableAsyncen tu clase principal (la que tiene@SpringBootApplication). - Añade
@Asyncen el métodosendSimpleEmaildelEmailService.
- Añade
- Plantillas de Correo (Templates): Para correos más complejos o con formato HTML, usa librerías de plantillas como Thymeleaf, FreeMarker o Mustache para crear modelos de correo y llenarlos dinámicamente.
- Configuraciones de Producción: En producción, verifica que tu firewall permita la salida de conexiones en el puerto 587 (o 465 para SSL).
- Límites de Gmail: Ten en cuenta los límites de envío diarios de Gmail (generalmente 500 correos por día para cuentas personales). Para mayores volúmenes, considera servicios de correo transaccional como SendGrid, Mailgun, AWS SES, etc.
Configurando las variables de entorno
Configurar variables de entorno es crucial para mantener las credenciales seguras y flexibilizar las configuraciones de tu aplicación Spring Boot en diferentes entornos. A continuación, una explicación concisa de cómo hacerlo para EMAIL_USER y EMAIL_SENHA en Windows, macOS y Docker Compose.
Windows
En Windows, puedes definir variables de entorno temporalmente vía línea de comandos o permanentemente a través de la configuración del sistema.
Temporalmente (para la sesión actual de la terminal):
Abre el Símbolo del sistema (Command Prompt) o PowerShell y usa:
set EMAIL_USER=tu_email@gmail.com
set EMAIL_SENHA=tu_contraseña_de_app
O en PowerShell:
$env:EMAIL_USER="tu_email@gmail.com"
$env:EMAIL_SENHA="tu_contraseña_de_app"
Luego, ejecuta tu aplicación Spring Boot desde la misma terminal.
Permanentemente (Sistema):
- Busca "Variables de Entorno" en el menú Inicio y selecciona "Editar las variables de entorno del sistema".
- En la ventana "Propiedades del Sistema", haz clic en "Variables de entorno...".
- En la sección "Variables de usuario para
" o "Variables del sistema", haz clic en "Nueva..." para añadir EMAIL_USERyEMAIL_SENHAcon sus respectivos valores. - Haz clic en "Aceptar" en todas las ventanas para guardar los cambios. Puede ser necesario reiniciar el sistema o la terminal para que los cambios surtan efecto.
macOS
En macOS, las variables de entorno se pueden definir temporalmente en la sesión de la terminal o añadirse a los archivos de configuración del shell para que sean persistentes.
Temporalmente (para la sesión actual de la terminal):
Abre la Terminal y usa:
export EMAIL_USER="tu_email@gmail.com"
export EMAIL_SENHA="tu_contraseña_de_app"
Luego, ejecuta tu aplicación Spring Boot desde la misma terminal.
Permanentemente (Perfil del Usuario):
Para que las variables se carguen automáticamente en cada nueva sesión de la terminal, añade las líneas export a uno de los siguientes archivos en tu directorio home:
~/.bash_profile(si usas Bash como shell por defecto)~/.zshrc(si usas Zsh como shell por defecto, que es el estándar en macOS Catalina y posterior)
Ejemplo para ~/.zshrc:
echo 'export EMAIL_USER="tu_email@gmail.com"' >> ~/.zshrc
echo 'export EMAIL_SENHA="tu_contraseña_de_app"' >> ~/.zshrc
source ~/.zshrc # Para aplicar los cambios inmediatamente
Docker Compose
En Docker Compose, puedes definir variables de entorno de algunas maneras en tu archivo docker-compose.yml. La forma más común y recomendada para credenciales es usar un archivo .env.
Usando un archivo .env (Recomendado para credenciales):
- Crea un archivo llamado
.enven el mismo directorio de tudocker-compose.yml. -
Añade tus variables de entorno a este archivo, una por línea:
# .env EMAIL_USER=tu_email@gmail.com EMAIL_SENHA=tu_contraseña_de_app -
En tu archivo
docker-compose.yml, referencia estas variables. Docker Compose cargará automáticamente las variables de un archivo.enven el mismo directorio.# docker-compose.yml version: '3.8' services: mi-app-spring: image: tu-imagen-spring-boot:latest # O usa build: . si vas a construir la imagen ports: - "8080:8080" environment: # Estas variables se leerán del archivo .env - EMAIL_USER=${EMAIL_USER} - EMAIL_SENHA=${EMAIL_SENHA} -
Ejecuta tu servicio de Docker Compose:
docker-compose up -d.
Alternativa (menos recomendada para credenciales sensibles en control de versiones):
También puedes definir las variables directamente en el docker-compose.yml en la sección environment, pero esto expone los valores en el archivo.
# docker-compose.yml
services:
mi-app-spring:
image: tu-imagen-spring-boot:latest
ports:
- "8080:8080"
environment:
EMAIL_USER: tu_email@gmail.com
EMAIL_SENHA: tu_contraseña_de_app # Evita esto en producción
Siempre prefiere el método del archivo .env y asegúrate de añadirlo a tu .gitignore para evitar que tus credenciales sean guardadas en el control de versiones.