Email Spring??

Buen dia, he visto varias implementaciones para enviar correos con Spring pero en todo caso cual es la mejor, que ventajas o desventajas hay en cada una de ellas??.
Hablando de SimpleMailMessage habla de un crear un hilo pero no acabo de entender como funciona, osea en este caso envía cada petición de envio en un hilo, estoy en lo correcto??

Aqui un ejemplo:

public void placeOrder(Order order) {
      // Do the business calculations...
      // Call the collaborators to persist the order...
      // Create a thread safe "copy" of the template message and customize it
             SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage);
             msg.setTo(order.getCustomer().getEmailAddress());
             msg.setText(
                                "Dear " + order.getCustomer().getFirstName()
                                + order.getCustomer().getLastName()
                                + ", thank you for placing order. Your order number is "
                                + order.getOrderNumber());
         try{
              this.mailSender.send(msg);
         }catch(MailException ex) {
          // simply log it and go on...
             System.err.println(ex.getMessage());
           }
}

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de ezamudio

no hay hilos ahí

En ese código que muestras, se manda el correo en el mismo hilo de ejecución. Es decir, el código desde donde invoques este método que muestras, no continuará hasta que se haya enviado el correo.

Lo que hablan de crear un hilo es que tengas un hilo dedicado al envío de correos, leyendo los pendientes a enviar de una cola y los procesos que quieren enviar un correo únicamente deben poner un correo en esa cola para que se envíe desde ese hilo dedicado.

Por ejemplo.

Este código me serviria para enviar 1000 correos sin problemas?? Es decir, que no vaya a tener problemas con encolamientos y esto haga que me tire mi app(WEB).

Imagen de ezamudio

cuantos quieras

Así como está tu código, si lo invocas así, el correo se envía en el momento en que invocas el método, usando ese hilo de ejecución. El envío de un correo es algo tardado, en lo que se establece la conexión, se hace el saludo, se establece una conexión segura (si es que configuras TLS/SSL que es bastante recomendable) y luego se envían los datos, se espera respuesta del server y finalmente se cierra la conexión. Y además de eso, puedes tener problemas si estás enviando correos desde distintos hilos porque algunos servidores de correo no permiten dos conexiones simultáneas usando la misma cuenta, pueden bloquearte uno de los envíos o incluso bloquear la cuenta porque eso lo consideran spam.

Por eso se recomienda tener un hilo dedicado que tome los correos a enviar de una cola, y que los procesos que quieran enviar correos, solamente crean su mensaje y lo ponen en esa cola. El efecto final es que solamente se está enviando un correo a la vez, desde el hilo dedicado, por lo que no tienes broncas de conexiones simultáneas, y además no hay retraso alguno en el hilo que quiere enviar el correo (no se queda pasmado en lo que se envía el correo).

En mi blog escribí hace mucho algo de thread pools, en este caso con un threadpool de un solo hilo la haces. Lo mejor es que hagas cierto refactoring de tu aplicación, para tener un componente dedicado a enviar correos ya hechos. Algo así:

public class Cartero {
  private ExecutorService tpool = Executors.newSingleThreadPoolExecutor();
  private JavaMailSender mailer; //este es el componente de Spring

  public void enviar(SimpleMailMessage mail) {
    tpool.execute(new Enviador(mail));
  }

  private class Enviador implements Runnable {
    private final SimpleMailMessage msg;
    private Enviador(SimpleMailMessage mail) { msg = mail; }

    public void run() {
      mailer.send(mail); //cachando MailException y dejando un log o algo
    }
  }
}

Eso lo invocas desde tu código simplemente así:

private Cartero cartero; //debes tener referencia al componente Cartero
public void placeOrder(Order order) {
  SimpleMailMessage msg = //creas tu mail tal cual como haces hoy
  cartero.enviar(msg);
}

Las ventajas ya las mencioné. La desventaja es que el correo no se envía en el momento, de modo que si es absolutamente esencial que sepas si el correo se pudo enviar o no, necesitas agregar algún mecanismo adicional al Cartero: en vez de Runnable, la clase Enviador debería ser Callable y devolver un boolean si se pudo enviar o algo así; y en el método enviar del cartero en vez de void se devuelve un Future con el resultado del envío (simplemente true o false). Cuando no te interese saber si se envió el correo o no, pues nomás invocas el método como puse en el ejemplo, y cuando te interese saber si se envía, guardas la referencia al Future para revisar el resultado (cuando se envíe, que podría tardar un rato si es que se están enviando muchos mails y la cola está algo larga). Y otra desventaja es que si detienes la aplicación y hay mails encolados, no se van a enviar, a menos que agregues un método que detenga el hilo que lo invoca hasta que se hayan enviado todos los pendientes, algo así:

@PreDestroy public void shutdown() {
  tpool.shutdown();
  int intentos = 0;
  while (!tpool.isTerminated() && intentos < 10) {
    intentos++;
    Thread.sleep(1000); //esperar un segundo (debe ir rodeado de try-catch)
  }
}

Con ese método en el Cartero, si tienes habilitado lo de context:annotation-config en tu applicationContext de Spring, entonces cuando detengas tu aplicación se invocará el shutdown que va a detener el thread pool y esperar hasta 10 segundos a que se terminen de enviar los correos (si después de 10 segundos no se han terminado de enviar, el método termina de todas formas y la secuencia de shutdown continuará).