Mostrando entradas con la etiqueta mail. Mostrar todas las entradas
Mostrando entradas con la etiqueta mail. Mostrar todas las entradas

domingo, 6 de marzo de 2022

Spring Boot Admin: Uso

Ya hemos visto un post sobre el uso de spring boot admin y como configurarlo cliente-servidor o a través de un Service Discovery como Eureka. En este post, veremos un poco más sobre su uso. Para ello, hemos utilizado las aplicaciones que configuramos en el anterior post, aquí puedes ver más información. Con las siguientes versiones de librerías:

  • Spring Boot: 2.5.7
  • Spring Admin: 2.5.4

Para mostrar el número de versión asociado a la aplicación debemos configurarlo a través del fichero pom.xml, el plugin spring-boot-maven-plugin y la opción build-info. De esta forma se creará de forma automática el fichero META-INF/build-info.properties que transmitirá la información al SBA. 

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <executions>
        <execution>
            <goals>
                <goal>build-info</goal>
            </goals>
        </execution>
    </executions>
</plugin>

También podemos añadir etiquetas a la información de nuestra aplicación que nos permita categorizarla, como puede ser el entorno donde se despliega. Estas etiquetas se trasladarán a través del endpoint info. Ejemplo de configuración:

#using the info endpoint
info.tags.environment=test


En el menú lateral Insights tendremos a nuestro alcance multitud de información, desde métricas, información del entorno, tareas programadas o propiedades de configuración. En el apartado de métricas podremos tener de un simple vistazo configuradas distintas mediciones que nos permitan comprobar como está funcionando la aplicación. 


También podemos modificar los niveles de trazas de log de cualquiera de las aplicaciones, posibilitando bajarlo o subirlo. 

Y aunque la documentación oficial indica que es necesario una configuración mínima. Haciendo uso de log4j2 y las versiones indicadas, no ha hecho falta modificar el fichero de configuración para que logs sean modificables y surja efecto el cambio a través de SBA. 


Para añadir interacción con los beans JMX, necesitamos por un lado añadir la dependencia org.jolokia.jolokia-core y por otro lado la propiedad spring.jmx.enabled en el fichero de configuración application.properties. De esta forma tendremos acceso de lectura de los atributos de los beans y en algunos caso incluso de escritura. Además también podremos realizar invocaciones sobre los métodos de dichos beans. 

Por último vamos a mostrar como podemos configurar notificaciones, estas se mostrarán cuando cambie las aplicaciones se detengan. Hay múltiples formas de realizar las notificaciones, por Slack, Telegram, Teams, etc. 
Nosotros utilizaremos el método tradicional de envío de correos. Y para ello vamos a utilizar MockMock un servidor SMTP muy básico que nos permitirá recibir los correos de prueba. Este servidor debemos arrancarlo con permisos de administrador para permitir el uso de los puertos y a través del siguiente comando, donde el primer parámetro es el puerto del servidor SMTP y el segundo el del navegador web que nos permitirá ver los correos:

sudo java -jar MockMock.jar -p 25 -h 8282

Y ahora debemos configurar SBA para el uso de correos. Por un lado le añadimos la dependencia spring-boot-starter-mail y por otro lado la configuración para el envío de mails:

spring.mail.host=localhost
spring.mail.port=25
spring.mail.properties.mail.transport.protocol=smtp
spring.boot.admin.notify.mail.to=receiver@example.com spring.boot.admin.notify.mail.from=sender@example.com

Ahora cuando una aplicación se caiga recibiremos el siguiente mail:


Espero que este post les ayude a mejorar la comprensión de esta increíble herramienta de monitorización como es Spring Boot Admin. 

sábado, 25 de abril de 2020

Java Mail con adjuntos y rutas relativas


Buenas, hoy vamos a ver como enviar un correo electrónico con Java Mail. Pero además veremos algo más importante, como añadir recursos (plantilla HTML, imagenes) a través de rutas relativas. En muchos ejemplos podrás ver como se añaden estos recursos pero siempre poniendo la ruta absoluta a dichos recursos. La clave para ello está en añadir los recursos como InputStream y no File.

El ejemplo lo dividiremos en 5 partes diferentes. Empecemos por la configuración del servidor, pensada para usar el servidor de SMTP de GMail

// Set properties
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");
// Create session & authenticate with mail server
Session session = Session.getInstance(props, new javax.mail.Authenticator() {
    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication(username, password);
    }
});

Luego creamos el mensaje con los datos de envío: destinatario, emisor, asunto, etc.

Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(fromEmail));
message.addRecipients(Message.RecipientType.TO, InternetAddress.parse(toEmail));
message.setSubject(messageSubject);

El siguiente paso es añadir el contenido del mensaje. Para ello por un lado crearemos el HTML del contenido en base a una plantilla concreta.

private void createTemplate(final MimeMultipart content, final String relFilePath,
      final String encoding, final String type) throws IOException, MessagingException {
    StringWriter writer = new StringWriter();
    IOUtils.copy(MailSenderUtil.class.getClassLoader().getResource(relFilePath).openStream(), writer,
            encoding);
    MimeBodyPart textPart = new MimeBodyPart();
    textPart.setText(writer.toString(), encoding, type);
    content.addBodyPart(textPart);
}

Y añadiremos una imagen como ejemplo de como podemos añadir adjuntos.

private void addImage(final MimeMultipart content, final String relFilePath, final String contentId,
        final String disposition) throws MessagingException, IOException {
    MimeBodyPart messageBodyPart = new MimeBodyPart();
    InputStream iStream = getClass().getClassLoader().getResource(relFilePath).openStream();
    DataSource fds = new InputStreamDataSource(iStream, contentId, "image/jpg");
    messageBodyPart.setDataHandler(new DataHandler(fds));
    messageBodyPart.setHeader("Content-ID", "<" + contentId + ">");
    messageBodyPart.setDisposition(disposition);
    messageBodyPart.setFileName(contentId);
    content.addBodyPart(messageBodyPart);
}

La imagen se encuentra dentro de nuestro proyecto y para ello indicamos su ruta relativa. Si simplemente obtuvieramos la ruta a través del método getFile() del objeto InputStream, a la hora de enviar el correo fallaría, porque indicaría que no es posible encontrarlo. En cambio, si le pasamos un InputStream no tendríamos problema para acceder al contenido del fichero. Pero para ello tendremos que crear una clase que extienda de javax.activation.DataSource para almacenar InputStream, puesto que por defecto no existe. Este sería su código.

public class InputStreamDataSource implements DataSource {
    byte[] bytes = null;
    private final String name;
    private final String contentType;

    public InputStreamDataSource(final InputStream inputStream, final String name, final String contentType)
            throws IOException {
        bytes = IOUtils.toByteArray(inputStream);
        this.name = name;
        this.contentType = contentType;
    }
    @Override
    public String getContentType() {
        return new MimetypesFileTypeMap().getContentType(contentType);
    }
    @Override
    public InputStream getInputStream() throws IOException {
        return new ByteArrayInputStream(bytes);
    }
    @Override
    public String getName() {
        return name;
    }
    @Override
    public OutputStream getOutputStream() throws IOException {
        throw new IOException("Read-only data");
    }
}

Por último solo nos quedaría realizar propiamente el envío del correo.

MimeMultipart content = new MimeMultipart("related");
createTemplate(content, "content/html/basic.html", "UTF-8", "html");
addImage(content, "content/images/header-wallpaper.jpg", "header-wallpaper", Part.INLINE);
message.setContent(content);
Transport.send(message);

Si quieres ver todo el código, lo tienes aquí.

sábado, 5 de noviembre de 2016

Spring Boot Mail: Configuración básica y para AWS SES

Seguimos con otro post sobre Spring Boot, en este caso relacionado con el envío de correos electrónicos. Y al final lo enlazaremos para poder usarlo con Amazon Simple Email Service.

Para empezar, lo básico. Añadir Spring boot  nuestro proyecto via Maven. Para ello indicamos que nuestro proyecto hereda de 'spring-boot-starter-parent' y que vamos a utilizar 'spring-boot-starter-mail'.

<parent>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-parent</artifactId>
   <version>1.4.0.RELEASE</version>
   <relativePath />
</parent>

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

Tras esto, viene la configuración básica para utilizar un servidor SMTP a través de Spring Boot. Por lo que como es habitual, rellenamos las propiedades apropiadas en el fichero application.properties.

spring.mail.host={TU_HOST}
spring.mail.port={HOST_PORT/25}
spring.mail.protocol=smtp

Tras esto, ya solo nos quedará inyectar en alguna de nuestras clases 'JavaMailSender'. Y utilizar a este mismo para enviar el correo. Así de facil y rápido. 


@Autowired
private JavaMailSender javaMailService;
......
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setTo( para );
mailMessage.setFrom( de);
mailMessage.setSubject( tituloCorreo);
mailMessage.setText( contenidoCorreo);
javaMailService.send( mailMessage );

Ahora vamos a ver como debemos configurarlo y usarlo si queremos enviar a través de AWS SES y además no enviar texto plano, sino HTML. El primer paso para ello será modificar la configuración de la siguiente forma:


spring.mail.host={TU_HOST}
spring.mail.password={TU_CLAVE_SES}
spring.mail.port=465
spring.mail.protocol=smtps
spring.mail.username={TU_USUARIO_SES}
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.ssl.enable = true
spring.mail.properties.mail.transport.protocol=smtps

Y a la hora de enviar el mail debemos dejar de usar 'SimpleMailMessage' y usar 'MimeMessage' y su Helper. Eso si, el 'body' del mensaje debe de tener sus etiquetas HTML. 


MimeMessage mailMessage = javaMailService.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper( mailMessage, false, "utf-8" );
helper.setTo( para );
helper.setFrom( de );
helper.setSubject( tituloCorreo );
mailMessage.setContent( contenidoCorreo , "text/html" );
javaMailService.send( mailMessage );