Ejemplo de JavaMail: enviar correo en Java usando SMTP

Hoy vamos a ver un ejemplo de JavaMail para enviar correos electrónicos en programas Java. El envío de correos electrónicos es una de las tareas comunes en las aplicaciones de la vida real y por eso Java proporciona una sólida API de JavaMail que podemos usar para enviar correos electrónicos utilizando un servidor SMTP. La API de JavaMail admite tanto la autenticación TLS como SSL para enviar correos electrónicos.

Ejemplo de JavaMail

Hoy aprenderemos cómo usar la API de JavaMail para enviar correos electrónicos utilizando un servidor SMTP sin autenticación, con autenticación TLS y SSL, y cómo enviar archivos adjuntos y adjuntar y usar imágenes en el cuerpo del correo electrónico. Para la autenticación TLS y SSL, estoy utilizando el servidor SMTP de GMail porque admite ambos. También puedes optar por utilizar un servidor de correo Java según las necesidades de tu proyecto. La API de JavaMail no es parte del JDK estándar, así que tendrás que descargarla desde su sitio web oficial, es decir, Página de inicio de JavaMail. Descarga la última versión de la implementación de referencia de JavaMail e inclúyela en la ruta de compilación de tu proyecto. El nombre del archivo jar será javax.mail.jar. Si estás utilizando un proyecto basado en Maven, simplemente agrega la siguiente dependencia en tu proyecto.

<dependency>
	<groupId>com.sun.mail</groupId>
	<artifactId>javax.mail</artifactId>
	<version>1.5.5</version>
</dependency>

El programa Java para enviar correos electrónicos contiene los siguientes pasos:

  1. Creando el objeto javax.mail.Session
  2. Creando el objeto javax.mail.internet.MimeMessage, debemos establecer diferentes propiedades en este objeto, como la dirección de correo electrónico del destinatario, el asunto del correo electrónico, el correo electrónico de respuesta, el cuerpo del correo electrónico, adjuntos, etc.
  3. Utilizando javax.mail.Transport para enviar el mensaje de correo electrónico.

La lógica para crear la sesión difiere según el tipo de servidor SMTP, por ejemplo, si el servidor SMTP no requiere autenticación, podemos crear el objeto Session con algunas propiedades simples, mientras que si requiere autenticación TLS o SSL, entonces la lógica para crear será diferente. Por lo tanto, crearé una clase de utilidad con algunos métodos de utilidad para enviar correos electrónicos y luego usaré este método de utilidad con diferentes servidores SMTP.

Ejemplo de Programa JavaMail

Nuestra clase EmailUtil que tiene un único método para enviar correos electrónicos se ve así a continuación, requiere javax.mail.Session y algunos otros campos requeridos como argumentos. Para mantenerlo simple, algunos de los argumentos están codificados directamente, pero puedes extender este método para pasarlos o leerlos desde algún archivo de configuración.

package com.journaldev.mail;

import java.io.UnsupportedEncodingException;
import java.util.Date;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

public class EmailUtil {

	/**
	 * Utility method to send simple HTML email
	 * @param session
	 * @param toEmail
	 * @param subject
	 * @param body
	 */
	public static void sendEmail(Session session, String toEmail, String subject, String body){
		try
	    {
	      MimeMessage msg = new MimeMessage(session);
	      // Establecer encabezados del mensaje
	      msg.addHeader("Content-type", "text/HTML; charset=UTF-8");
	      msg.addHeader("format", "flowed");
	      msg.addHeader("Content-Transfer-Encoding", "8bit");

	      msg.setFrom(new InternetAddress("[email protected]", "NoReply-JD"));

	      msg.setReplyTo(InternetAddress.parse("[email protected]", false));

	      msg.setSubject(subject, "UTF-8");

	      msg.setText(body, "UTF-8");

	      msg.setSentDate(new Date());

	      msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toEmail, false));
	      System.out.println("Message is ready");
    	  Transport.send(msg);  

	      System.out.println("EMail Sent Successfully!!");
	    }
	    catch (Exception e) {
	      e.printStackTrace();
	    }
	}
}

Observa que estoy configurando algunas propiedades de encabezado en el MimeMessage, estas son utilizadas por los clientes de correo electrónico para renderizar y mostrar adecuadamente el mensaje de correo electrónico. El resto del programa es simple y se entiende por sí mismo. Ahora creemos nuestro programa para enviar correo electrónico sin autenticación.

Enviar correo electrónico en Java usando SMTP sin autenticación

package com.journaldev.mail;

import java.util.Properties;

import javax.mail.Session;

public class SimpleEmail {
	
	public static void main(String[] args) {
		
	    System.out.println("SimpleEmail Start");
		
	    String smtpHostServer = "smtp.example.com";
	    String emailID = "[email protected]";
	    
	    Properties props = System.getProperties();

	    props.put("mail.smtp.host", smtpHostServer);

	    Session session = Session.getInstance(props, null);
	    
	    EmailUtil.sendEmail(session, emailID,"SimpleEmail Testing Subject", "SimpleEmail Testing Body");
	}

}

Observe que estoy utilizando Session.getInstance() para obtener el objeto de sesión pasando el objeto Properties. Necesitamos establecer la propiedad mail.smtp.host con el host del servidor SMTP. Si el servidor SMTP no está en el puerto predeterminado (25), entonces también deberá establecer la propiedad mail.smtp.port. Simplemente ejecute este programa con su servidor SMTP sin autenticación y configurando la dirección de correo electrónico del destinatario como su propia dirección de correo electrónico y recibirá el correo electrónico en poco tiempo. El programa es fácil de entender y funciona bien, pero en la vida real la mayoría de los servidores SMTP utilizan algún tipo de autenticación como autenticación TLS o SSL. Así que ahora veremos cómo crear un objeto de sesión para estos protocolos de autenticación.

Enviar correo electrónico en Java SMTP con autenticación TLS

package com.journaldev.mail;

import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;

public class TLSEmail {

	/**
	   Outgoing Mail (SMTP) Server
	   requires TLS or SSL: smtp.gmail.com (use authentication)
	   Use Authentication: Yes
	   Port for TLS/STARTTLS: 587
	 */
	public static void main(String[] args) {
		final String fromEmail = "[email protected]"; //requires valid gmail id
		final String password = "mypassword"; // correct password for gmail id
		final String toEmail = "[email protected]"; // can be any email id 
		
		System.out.println("TLSEmail Start");
		Properties props = new Properties();
		props.put("mail.smtp.host", "smtp.gmail.com"); //SMTP Host
		props.put("mail.smtp.port", "587"); //TLS Port
		props.put("mail.smtp.auth", "true"); //enable authentication
		props.put("mail.smtp.starttls.enable", "true"); //enable STARTTLS
		
                //crear objeto Authenticator para pasar como argumento en Session.getInstance
		Authenticator auth = new Authenticator() {
			//sobrescribir el método getPasswordAuthentication
			protected PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication(fromEmail, password);
			}
		};
		Session session = Session.getInstance(props, auth);
		
		EmailUtil.sendEmail(session, toEmail,"TLSEmail Testing Subject", "TLSEmail Testing Body");
		
	}

	
}

Dado que estoy utilizando el servidor SMTP de Gmail que está accesible para todos, puedes establecer las variables correctas en el programa anterior y ejecutarlo por ti mismo. ¡Créeme, funciona! 🙂

Ejemplo de Java SMTP con autenticación SSL

package com.journaldev.mail;

import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;

public class SSLEmail {

	/**
	   Outgoing Mail (SMTP) Server
	   requires TLS or SSL: smtp.gmail.com (use authentication)
	   Use Authentication: Yes
	   Port for SSL: 465
	 */
	public static void main(String[] args) {
		final String fromEmail = "[email protected]"; //requires valid gmail id
		final String password = "mypassword"; // correct password for gmail id
		final String toEmail = "[email protected]"; // can be any email id 
		
		System.out.println("SSLEmail Start");
		Properties props = new Properties();
		props.put("mail.smtp.host", "smtp.gmail.com"); //SMTP Host
		props.put("mail.smtp.socketFactory.port", "465"); //SSL Port
		props.put("mail.smtp.socketFactory.class",
				"javax.net.ssl.SSLSocketFactory"); //SSL Factory Class
		props.put("mail.smtp.auth", "true"); //Enabling SMTP Authentication
		props.put("mail.smtp.port", "465"); //SMTP Port
		
		Authenticator auth = new Authenticator() {
			//anular el método getPasswordAuthentication
			protected PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication(fromEmail, password);
			}
		};
		
		Session session = Session.getDefaultInstance(props, auth);
		System.out.println("Session created");
	        EmailUtil.sendEmail(session, toEmail,"SSLEmail Testing Subject", "SSLEmail Testing Body");

	        EmailUtil.sendAttachmentEmail(session, toEmail,"SSLEmail Testing Subject with Attachment", "SSLEmail Testing Body with Attachment");

	        EmailUtil.sendImageEmail(session, toEmail,"SSLEmail Testing Subject with Image", "SSLEmail Testing Body with Image");

	}

}

El programa es casi igual que la autenticación TLS, solo algunas propiedades son diferentes. Como puedes ver, estoy llamando a algunos otros métodos de la clase EmailUtil para enviar adjuntos e imágenes por correo electrónico, pero aún no los he definido. De hecho, los mantuve para mostrarlos más tarde y mantenerlo simple al inicio del tutorial.

Ejemplo de JavaMail – enviar correo en Java con adjunto

Para enviar un archivo como adjunto, necesitamos crear un objeto de javax.mail.internet.MimeBodyPart y javax.mail.internet.MimeMultipart. Primero agregue la parte del cuerpo para el mensaje de texto en el correo electrónico y luego use FileDataSource para adjuntar el archivo en la segunda parte del cuerpo multiparte. El método se ve así.

/**
 * Utility method to send email with attachment
 * @param session
 * @param toEmail
 * @param subject
 * @param body
 */
public static void sendAttachmentEmail(Session session, String toEmail, String subject, String body){
	try{
         MimeMessage msg = new MimeMessage(session);
         msg.addHeader("Content-type", "text/HTML; charset=UTF-8");
	     msg.addHeader("format", "flowed");
	     msg.addHeader("Content-Transfer-Encoding", "8bit");
	      
	     msg.setFrom(new InternetAddress("[email protected]", "NoReply-JD"));

	     msg.setReplyTo(InternetAddress.parse("[email protected]", false));

	     msg.setSubject(subject, "UTF-8");

	     msg.setSentDate(new Date());

	     msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toEmail, false));
	      
         // Crear la parte del cuerpo del mensaje
         BodyPart messageBodyPart = new MimeBodyPart();

         // Llenar el mensaje
         messageBodyPart.setText(body);
         
         // Crear un mensaje multiparte para el adjunto
         Multipart multipart = new MimeMultipart();

         // Establecer parte del mensaje de texto
         multipart.addBodyPart(messageBodyPart);

         // La segunda parte es el adjunto
         messageBodyPart = new MimeBodyPart();
         String filename = "abc.txt";
         DataSource source = new FileDataSource(filename);
         messageBodyPart.setDataHandler(new DataHandler(source));
         messageBodyPart.setFileName(filename);
         multipart.addBodyPart(messageBodyPart);

         // Enviar las partes completas del mensaje
         msg.setContent(multipart);

         // Enviar mensaje
         Transport.send(msg);
         System.out.println("EMail Sent Successfully with attachment!!");
      }catch (MessagingException e) {
         e.printStackTrace();
      } catch (UnsupportedEncodingException e) {
		 e.printStackTrace();
	}
}

El programa puede parecer complejo a primera vista, pero es simple. Simplemente crea una parte del cuerpo para el mensaje de texto y otra parte del cuerpo para el archivo adjunto, y luego agrégalas al multipart. También puedes extender este método para adjuntar varios archivos.

Ejemplo de JavaMail: enviar correo en Java con imagen

Dado que podemos crear un cuerpo de mensaje HTML, si el archivo de imagen está ubicado en alguna ubicación del servidor, podemos usar el elemento img para mostrarlo en el mensaje. Pero a veces queremos adjuntar la imagen en el correo electrónico y luego usarla en el cuerpo del correo electrónico en sí. Seguramente has visto muchos correos electrónicos que tienen archivos de imagen adjuntos y también se usan en el mensaje de correo electrónico. El truco es adjuntar el archivo de imagen como cualquier otro archivo adjunto y luego establecer el encabezado Content-ID para el archivo de imagen y luego usar el mismo ID de contenido en el cuerpo del mensaje de correo electrónico con <img src='cid:image_id'>.

/**
 * Utility method to send image in email body
 * @param session
 * @param toEmail
 * @param subject
 * @param body
 */
public static void sendImageEmail(Session session, String toEmail, String subject, String body){
	try{
         MimeMessage msg = new MimeMessage(session);
         msg.addHeader("Content-type", "text/HTML; charset=UTF-8");
	     msg.addHeader("format", "flowed");
	     msg.addHeader("Content-Transfer-Encoding", "8bit");
	      
	     msg.setFrom(new InternetAddress("[email protected]", "NoReply-JD"));

	     msg.setReplyTo(InternetAddress.parse("[email protected]", false));

	     msg.setSubject(subject, "UTF-8");

	     msg.setSentDate(new Date());

	     msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toEmail, false));
	      
         // Crear la parte del cuerpo del mensaje
         BodyPart messageBodyPart = new MimeBodyPart();

         messageBodyPart.setText(body);
         
         // Crear un mensaje multipart para el archivo adjunto
         Multipart multipart = new MimeMultipart();

         // Establecer la parte del mensaje de texto
         multipart.addBodyPart(messageBodyPart);

         // La segunda parte es el archivo adjunto de imagen
         messageBodyPart = new MimeBodyPart();
         String filename = "image.png";
         DataSource source = new FileDataSource(filename);
         messageBodyPart.setDataHandler(new DataHandler(source));
         messageBodyPart.setFileName(filename);
         // El truco es agregar aquí el encabezado de identificación de contenido
         messageBodyPart.setHeader("Content-ID", "image_id");
         multipart.addBodyPart(messageBodyPart);

         // Tercera parte para mostrar la imagen en el cuerpo del correo electrónico
         messageBodyPart = new MimeBodyPart();
         messageBodyPart.setContent("

Attached Image

" + "", "text/html"); multipart.addBodyPart(messageBodyPart); // Establecer el mensaje multipart en el mensaje de correo electrónico msg.setContent(multipart); // Enviar mensaje Transport.send(msg); System.out.println("EMail Sent Successfully with image!!"); }catch (MessagingException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } }

Consejos para solucionar problemas de la API JavaMail

  1. java.net.UnknownHostException ocurre cuando su sistema no puede resolver la dirección IP del servidor SMTP, puede estar incorrecta o no accesible desde su red. Por ejemplo, el servidor SMTP de GMail es smtp.gmail.com y si uso smtp.google.com, obtendré esta excepción. Si el nombre de host es correcto, intente hacer ping al servidor a través de la línea de comandos para asegurarse de que sea accesible desde su sistema.

    pankaj@Pankaj:~/CODE$ ping smtp.gmail.com
    PING gmail-smtp-msa.l.google.com (74.125.129.108): 56 datos bytes
    64 bytes desde 74.125.129.108: icmp_seq=0 ttl=46 tiempo=38.308 ms
    64 bytes desde 74.125.129.108: icmp_seq=1 ttl=46 tiempo=42.247 ms
    64 bytes desde 74.125.129.108: icmp_seq=2 ttl=46 tiempo=38.164 ms
    64 bytes desde 74.125.129.108: icmp_seq=3 ttl=46 tiempo=53.153 ms
    
  2. Si tu programa está atascado en la llamada al método send() de Transport, verifica que el puerto SMTP sea correcto. Si es correcto, utiliza telnet para verificar que sea accesible desde tu máquina, obtendrás una salida como la siguiente.

    pankaj@Pankaj:~/CODE$ telnet smtp.gmail.com 587
    Trying 2607:f8b0:400e:c02::6d...
    Connected to gmail-smtp-msa.l.google.com.
    Escape character is '^]'.
    220 mx.google.com ESMTP sx8sm78485186pab.5 - gsmtp
    HELO
    250 mx.google.com at your service
    

Eso es todo para el ejemplo de JavaMail para enviar correos electrónicos en Java usando un servidor SMTP con diferentes protocolos de autenticación, adjuntos e imágenes. Espero que esto resuelva todas tus necesidades para enviar correos electrónicos en programas Java.

Source:
https://www.digitalocean.com/community/tutorials/javamail-example-send-mail-in-java-smtp