Enviando E-mail com Spring Boot

Em muitas aplicações, o envio de e-mails é uma funcionalidade essencial — seja para notificar usuários, confirmar cadastros ou acompanhar eventos internos da aplicação. Neste post, vamos ver como integrar esse recurso de forma prática e eficiente usando o Spring Boot.

Primeiro, precisamos incluir a dependência Spring Boot Starter Mail no arquivo pom.xml para habilitar o suporte ao envio de e-mails na aplicação.

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

Em seguida, vamos configurar a conta de e-mail que será usada para o envio das mensagens. Para este tutorial, utilizaremos o Mailtrap, uma ferramenta ideal para testes, que permite capturar e visualizar e-mails de forma segura e prática, sem enviá-los de fato para destinatários reais. Nosso application.properties ficará assim.

spring.mail.host=sandbox.smtp.mailtrap.io
spring.mail.port=587
spring.mail.username=user
spring.mail.password=*********
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true

Com as configurações prontas, é hora de criar um controller responsável por disparar o envio da mensagem.

@RestController
public class MailController {
    
    private JavaMailSender mailSender;

    public MailController(JavaMailSender mailSender) {
        this.mailSender = mailSender;
    }

    @GetMapping("/mail")
    public ResponseEntity<Void> send(){
        SimpleMailMessage message = new SimpleMailMessage();
        message.setTo("rodrigo@botecodigital.dev.br");
        message.setSubject("Mensagem de teste");
        message.setText("Esta é uma mensagem de teste!");
        message.setFrom("contato@botecodigital.dev.br");

        mailSender.send(message);        

        return ResponseEntity.ok().build();
    }
}

Neste trecho de código, utilizamos a injeção de dependência para receber uma instância de JavaMailSender via construtor (linha 6), que será responsável por enviar os e-mails. Na linha 12, instanciamos um SimpleMailMessage, que representa a mensagem que será enviada. Esse objeto oferece métodos para configurar os principais campos do e-mail: setTo() para o destinatário, setSubject() para o assunto, setText() para o corpo da mensagem, setFrom() para o remetente, além de setCc() e setBcc() para cópia e cópia oculta, respectivamente. Por fim, o envio é feito através do método send(), passando o objeto da mensagem, na linha 18.

Utilizando Thymeleaf para o corpo do e-mail

Para criar e-mails com conteúdo em HTML de forma dinâmica, podemos utilizar o Template Engine Thymeleaf, aproveitando todo o poder das suas diretivas. O primeiro passo é criar um template HTML. Vamos adicionar esse arquivo em resources/templates/mail/message.html.

<!DOCTYPE html>
<html lang="pt-BR" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Seja bem-vindo</title>
</head>
<body>
    <p>Olá <th:block th:text="${nome}"></th:block>!</p>

    <p>Você se cadastrou em <th:block th:text="${#temporals.format(data,'dd/MM/yyyy hh:mm')}" /></p>

    <p>Com os itens: </p>
    <ul>
        <li th:each="item : ${itens}" th:text="${item}"></li>
    </ul>
</body>
</html>

Em seguida, vamos criar o método no controller responsável por enviar a mensagem.

@Autowired
private TemplateEngine templateEngine;

@GetMapping("/mail-template")
public ResponseEntity<Void> sendTemplate(){

    try{
        MimeMessage mimeMessage = mailSender.createMimeMessage();
        MimeMessageHelper message = new MimeMessageHelper(mimeMessage);
        message.setTo("rodrigo@botecodigital.dev.br");
        message.setFrom("contato@botecodigital.dev.br");
        message.setSubject("Mensagem de teste");
            
        Context ctx = new Context();
        ctx.setVariable("nome", "Rodrigo Aramburu");
        ctx.setVariable("data", LocalDateTime.now());
        ctx.setVariable("itens", Arrays.asList("Item 1", "Item 2", "Item 3"));
        String body = templateEngine.process("mail/message", ctx);
        message.setText(body, true);

        mailSender.send(mimeMessage);        
    }catch( MessagingException e){
        e.printStackTrace();
    }

    return ResponseEntity.ok().build();
}

Começamos injetando o objeto TemplateEngine com a anotação @Autowired. Ele será responsável por processar o nosso template HTML e gerar o conteúdo da mensagem a ser enviada.

No método do controller, em vez de utilizar um SimpleMailMessage, criamos um MimeMessage usando o método createMimeMessage do JavaMailSender. Em seguida, instanciamos um MimeMessageHelper, passando o MimeMessage como parâmetro. É nesse objeto MimeMessageHelper que vamos configurar os campos do e-mail, assim como fizemos anteriormente com o SimpleMailMessage.

Na linha 14, criamos um objeto Context, onde vamos adicionar as variáveis que serão utilizadas no nosso template. Usamos o método setVariable para incluir valores como um nome, uma data e uma lista de itens que serão exibidos no template.

Para gerar o corpo do e-mail, chamamos o método templateEngine.process() na linha 18, passando o caminho do arquivo HTML e o objeto Context que contém as variáveis. Esse método retorna uma String com o conteúdo processado, que é então passado para o método setText, com o segundo parâmetro definido como true para indicar que o conteúdo está em formato HTML.

Por fim, chamamos o método mailSender.send(), passando o objeto MimeMessage para enviar o e-mail.

Enviando um e-mail com anexo

Enviar um arquivo anexado é bem simples: basta utilizar o método addAttachment do objeto MimeMessageHelper, passando o nome do arquivo e um objeto File.

MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper message = new MimeMessageHelper(mimeMessage, true);
message.setTo("rodrigo@botecodigital.dev.br");
message.setFrom("contato@botecodigital.dev.br");
message.setSubject("Mensagem de teste");

message.setText("Segue arquivo anexo");

File file = ResourceUtils.getFile("classpath:texto.txt");
message.addAttachment(file.getName(), file);

mailSender.send(mimeMessage);   

Enviando um e-mail com uma imagem inline

Para enviar um e-mail com uma imagem inline no corpo da mensagem é bastante simples. Utilizaremos um template Thymeleaf para escrever nosso HTML.

<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>E-mail com imagem inline</title>
</head>
<body>
    <img th:src="|cid:imageDuke|" alt="Duke segurando uma taça">    
</body>
</html>

Perceba que na tag de imagem, no atributo src, utilizamos cid:imageDuke. O nome imageDuke é o identificador que vamos atribuir à imagem quando a adicionarmos ao objeto de imagem no código Java.

Agora, vamos ao código que adiciona a imagem à mensagem.

MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper message = new MimeMessageHelper(mimeMessage, true);
message.setTo("rodrigo@botecodigital.dev.br");
message.setFrom("contato@botecodigital.dev.br");
message.setSubject("Mensagem de teste");
            
Context ctx = new Context();
            
byte[] imageBytes = Files.readAllBytes(ResourceUtils.getFile("classpath:duke.png").toPath());
InputStreamSource imageSource = new ByteArrayResource(imageBytes);
message.addInline("imageDuke", imageSource, "image/png");

String body = templateEngine.process("mail/inline", ctx);

message.setText(body, true);
mailSender.send(mimeMessage);

Primeiro, lemos o arquivo de imagem para um array de bytes (linha 9). Em seguida, criamos um InputStream a partir desses bytes e adicionamos a imagem usando o método addInline. Esse método recebe o identificador da imagem (o mesmo nome que usamos no atributo src da tag <img> no HTML), o InputStream da imagem e o MIME type do arquivo. E pronto, é só enviar o e-mail.

A abstração fornecida pelo Spring Boot Starter Mail torna o envio de e-mails muito simples, como vimos neste post. Espero que tenha sido útil. T++!