Skip to content

Java vs Elixir: Envío de Correos

Comparativa real de implementación de envío de correos SMTP con Gmail en Spring Boot vs Phoenix/Swoosh, basada en el código fuente de Te Llevo App.

Lo que un veterano te da, lo que un joven con energía no posee… los dichosos CA certificates

5 iteraciones TLS para poder enviar un correo electrónico desde Elixir:
cacerts: :undefinedverify_nonecacertfilemax_path_length_reachedverify_none otra vez.

Todo para enviar un correo electrónico desde Elixir.

En Java: agregas la dependencia, copias 30 líneas de código, y funciona de inmediato. El JDK trae su propio almacén de certificados CA raíz ($JAVA_HOME/lib/security/cacerts). STARTTLS con Gmail funciona out of the box. Sin configurar nada extra.


No es que Elixir sea malo. Swoosh tiene una API hermosa, el pipeline funcional es 3× más conciso que Jakarta Mail, y el adapter de desarrollo (correos en memoria, sin enviar) es una maravilla.

Pero hay algo que un ecosistema con décadas de madurez te da: que alguien ya pensó en las esquinas del sistema y las dejó resueltas para que tú no tengas que convertirte en experto en TLS/SSL para enviar un simple correo de registro.

La madurez empresarial de Java no es solo boilerplate. Es confiabilidad.

Elixir me encanta, pero este round se lo lleva Java. Y está genial admitirlo. ⚖️

Comparativa real de implementación de envío de correos SMTP con Gmail en Spring Boot (Java) vs Phoenix/Swoosh (Elixir), basada en el código fuente de Te Llevo App.

JavaElixir
Spring Boot + Jakarta MailPhoenix + Swoosh
📁 114 líneas📁 ~80 líneas
🔧 Gmail SMTP🔧 Gmail SMTP

Código real de ambos proyectos. La diferencia en complejidad y expresividad es evidente.

@Service
@Primary
public class EmailGoogleWorkspaceService implements SendMail {
private final Environment environment;
public EmailGoogleWorkspaceService(Environment environment) {
this.environment = environment;
}
public void sendHtmlEmail(String to, String subject, String htmlContent)
throws MessagingException {
Properties props = new Properties();
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.host", "smtp.gmail.com");
props.put("mail.smtp.port", "587");
String userName = environment.getProperty("...");
String password = environment.getProperty("...");
Session session = Session.getInstance(props, new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(userName, password);
}
});
Message mensaje = new MimeMessage(session);
mensaje.setFrom(new InternetAddress("desarrollo@tellevoapp.cl"));
mensaje.setRecipients(Message.RecipientType.TO,
InternetAddress.parse(to));
mensaje.setSubject(subject);
mensaje.setContent(htmlContent, "text/html");
Transport.send(mensaje);
}
}

Evaluación de los aspectos más relevantes entre ambas implementaciones:

AspectoJava (Spring Boot)Elixir (Phoenix/Swoosh)
Bibliotecajakarta.mail (bajo nivel)swoosh (alto nivel)
Dependencias extraSolo jakarta.mailswoosh + gen_smtp
Líneas de código~114 + interfaz + facades~80 (con template y logging)
Config SMTPHardcodeada en PropertiesDeclarativa en runtime.exs
Construcción de emailManual (MimeMessage, InternetAddress…)Pipeline funcional inmutable
AutenticaciónAuthenticator anónimoConfiguración declarativa
EnvíoTransport.send(message)Mailer.deliver(email)
CA Certificates✅ JDK built-in (cacerts)❌ Erlang no trae CA store de fábrica
Error handlingtry/catch + Checked ExceptionsPattern matching: {:ok, _} | {:error, _}
TestingMockear JavaMailSender o TransportSwoosh.Adapters.Test (nativo sin mocks)
Interfaz/ContratoInterface SendMail obligatoria para DINo requiere interfaces ni types extras
Desarrollo localSMTP real o herramienta externa (MailHog)Swoosh.Adapters.Local visible en /mailbox
Templates HTMLConcatenación de strings o motor de plantillas~s"""...""" o HEEx con Componentes
Thread safetyStateless (cada llamada crea instancias)Proceso supervisado OTP

Análisis detallado de cada stack basado en la experiencia de producción.

☕ Java / Spring Boot

  • CA certs built-in: El JDK trae su propio almacén de certificados raíz. El handshake TLS/STARTTLS con Gmail funciona out of the box sin tocar nada.
  • Sin dependencias de terceros: Spring Boot Starter Mail provee todo lo necesario de manera estandarizada.
  • Madurez: Jakarta Mail existe desde 1997. Hay documentación masiva y miles de soluciones para cada caso posible.
  • Demasiado Boilerplate: Configurar propiedades, sesiones, autenticadores y mensajes mutables requiere alrededor de 20 a 30 líneas de código repetitivo.
  • Bajo nivel de abstracción: El correo no se trata como una estructura de datos inmutable, sino como un objeto mutable complejo.
  • Sin adapter local para dev: Obliga a configurar un servidor SMTP local de terceros (Mailpit, MailHog) o enviar correos reales durante el desarrollo.

💧 Elixir / Phoenix

  • Pipeline Funcional: Estilo claro e intuitivo con operador pipe (|>). Componible y fácil de leer.
  • Adapter de Desarrollo Novedoso: Swoosh permite almacenar correos en memoria y visualizarlos en un buzón de desarrollo en /mailbox de manera nativa.
  • Test Adapter Integrado: Verificar si un correo se envió y validar su contenido se hace con aserciones nativas sencillas sin necesidad de mocks complejos.
  • Ausencia de CA Store: Erlang/OTP no hereda el almacén de certificados del SO fácilmente. Requiere apuntar manualmente a rutas como /etc/ssl/certs/ca-certificates.crt en Linux y puede dar problemas estrictos como max_path_length_reached.
  • Dependencias frágiles: Requiere obligatoriamente gen_smtp por debajo de Swoosh. Si la configuración de dependencias es incorrecta, los errores en cascada pueden ser confusos.

Las 5 iteraciones necesarias para lograr el envío de correos seguro en Elixir, comparado con 0 configuraciones extras en Java:

PasoPuertoTLSEstadoCausa Raíz / Solución
1587tls: :always❌ :tls_failedNo se encuentra el almacén de certificados CA en Erlang.
2465ssl: true❌ cacerts: :undefinedverify: :verify_peer fallando debido a la falta de CA store.
3465ssl: true✅ FuncionóSe deshabilitó la validación temporalmente con verify_none.
4587tls: :always❌ max_path_length_reachedEl motor SSL de Erlang es más estricto con los certificados de Gmail de lo habitual.
5587tls: :always✅ FuncionaSolución pragmática: Comunicación cifrada TLS pero con verify: :verify_none.

☕ Elige Java cuando...

  • Trabajando en entornos corporativos con políticas estrictas de validación TLS (sin excepciones de verificación peer).
  • El equipo posee un fuerte background en Spring Boot.
  • La infraestructura empresarial requiere configuraciones muy complejas de Single Sign-On, OAuth2 o Active Directory para el servicio de correo.

💧 Elige Elixir cuando...

  • Estás desarrollando un proyecto moderno sobre la pila Phoenix.
  • Valoras un flujo de testing limpio, rápido y con herramientas integradas de fábrica.
  • Deseas optimizar la velocidad de desarrollo y tener un código 3 veces más conciso.
CriterioGanadorDetalle
Facilidad inicial (time to first email)JavaCertificados CA integrados en JDK. Cero fricción inicial.
Concisión del códigoElixir~5 líneas de lógica limpia vs ~30+ de boilerplate en Java.
Experiencia de desarrollo (DX)ElixirMailbox local incorporado, inmutabilidad de datos.
Manejo de TLS/SSLJavaJDK cacerts funciona out of the box sin depurar rutas.
TestabilidadElixirTest adapter nativo y aserciones rápidas de Swoosh.
Madurez y ecosistemaJavaJakarta Mail tiene décadas de robustez probada en la industria.

Puntuación: ⚖️ Empate Técnico (3 / 3)

Section titled “Puntuación: ⚖️ Empate Técnico (3 / 3)”
  • Java (3/6): Facilidad de Red/TLS, Certificados robustos, Madurez.
  • Elixir (3/6): Concisión, DX (Buzón local), Testabilidad.