top of page

Enviando (e também disparando) e-mails em Java

  • Foto do escritor: Eduardo Nepomuceno da Rocha
    Eduardo Nepomuceno da Rocha
  • 16 de fev. de 2024
  • 5 min de leitura

Aproveitando o assunto proposto pelo último post, que apresentava brevemente uma ferramenta de automação Java, trato hoje de um dos motivos pelos quais ela é mais usada: agendamento de e-mails. Um uso muito comum do Spring Batch com e-mails é o disparo típico de comércio eletrônico, promoções, envios de boletos e outras tarefas comerciais. Nesse texto, o foco maior será na ferramenta de envio de e-mails mais utilizada no mercado com Spring Boot, e sua configuração (que é muito prática). Apresentarei dois projetos simples, que servem de base para começar algo maior com o uso dessa ferramenta de fácil configuração.



A dependência do pom que deve ser acrescentada para o uso do envio de e-mails Spring é o Spring Boot Starter E-mail. No meu caso, apresentarei a versão 2. Há pequenas mudanças para a versão 3, então é necessário estar atento a essas atualizações. Por atuar em um projeto com versão de Java mais antiga atualmente, resolvi trazer a versão 2, mas que também é perfeitamente compatível com Spring Boot 3 e Java 17 ou 21.


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

A primeira tarefa a ser realizada é escolher um serviço SMTP. Eu escolhi o do Google. Para enviar e-mails pelo servidor do Google em suas aplicações é necessário colocar autenticação de dois fatores no seu e-mail. Depois disso, será possível criar uma senha para usar em suas aplicações. Acredito que um tutorial sobre caiba em outro contexto, mas é fácil encontrar vídeos ensinando. Depois, é necessário colocar essas informações em um application.properties. Eu particularmente gosto de criar uma pasta específica para isso. Costumo criar dentro de resources uma pasta com nome env e dentro dela um arquivo mail.properties, mas onde estará a informação fica a critério do desenvolvedor. Depende da aplicação e da quantidade de ferramentas utilizadas. No que envolve configuração, acredito que fique mais legível pensando em manutenção da aplicação.


# Configuracoes basicas para envio de e-mail
mail.smtp.host = smtp.gmail.com
mail.smtp.port = 587
mail.smtp.username = seuemail@gmail.com
mail.smtp.password = senhadogmail 

Essas configurações são utilizadas na configuração dentro do Spring Boot. Vejamos agora a classe de configuração:


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import java.util.Properties;

@Configuration
@PropertySource("classpath:env/mail.properties")

public class EmailConfig {
    @Autowired
    private Environment environment;
    @Bean
    public JavaMailSender mailSender() {
        JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
        javaMailSender.setHost(environment.getProperty("mail.smtp.host"));        javaMailSender.setPort(environment.getProperty("mail.smtp.port", Integer.class));
        javaMailSender.setUsername(environment.getProperty("mail.smtp.username"));
        javaMailSender.setPassword(environment.getProperty("mail.smtp.password"));
        Properties properties = javaMailSender.getJavaMailProperties();        properties.put("mail.transport.protocol", "smtp");
        properties.put("mail.smtp.auth", "true");
        properties.put("mail.smtp.starttls.enable", "true");
        properties.put("mail.debug", "true");
        return javaMailSender;
    }
}

Comecemos pelas anotações da classe de configuração. @Configuration já é uma notação conhecida do Spring, que serve para qualquer configuração que o Spring deve ler antes de começar a executar a aplicação. A anotação @PropertySource aponta para a fonte das informações smtp. No caso, classpath indica o resources, e o que está dentro dele a pasta criada e o properties. O JavaMailSender deve ser anotado como Bean para que esteja disponível em todo o contexto do Spring. Environment é uma classe do Spring, que será utilizada para configurar as informações do JavaMailSender. A classe properties é um mapa para o qual são configuradas outras propriedades do JavaMailSender. Para enviar e-mail, criei uma classe de MensagemEmail. Ela varia de acordo com as especificações do negócio, da necessidade do usuário. Minha classe ficou assim:


import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class MensagemEmail {
    private String assunto;
    private String texto;
    private String remetente;
    private List<String> destinatarios;
    private String anexo;
}

Utilizei a dependência do Lombok para não precisar escrever construtores, gets e sets, além de utilizar o padrão Builder. Não é uma prática obrigatória, porém utilizei uma classe de serviço de e-mail, para poder usar no padrão de APIs. Criei dois métodos, um para testar envio com mensagem de texto, e depois outro para testar envio de arquivo em anexo. Há uma diferença simples entre ambos. No projeto Spring Batch, injetei a dependência do Service para testar a automação. A partir da verificação do funcionamento da aplicação, basta utilizar outras ferramentas do Batch, como o Job Scheduler, Trigger e outros recursos para disparar um método, conforme a necessidade do projeto. Veja abaixo a classe de Service:


import com.eduardondarocha.mindsimapp.model.MensagemEmail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import javax.mail.internet.MimeMessage;
@Service
public class EmailService {
    @Autowired
    private JavaMailSender javaMailSender;
    public void sendEmailWithFile(MensagemEmail mensagemEmail){
        try {
            MimeMessage mimeMessage = javaMailSender.createMimeMessage();
            MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage,true, "utf-8");
            mimeMessageHelper.setFrom(mensagemEmail.getRemetente());
            mimeMessageHelper.setSubject(mensagemEmail.getAssunto());
            mimeMessageHelper.setText(mensagemEmail.getTexto(), true);
            mimeMessageHelper.setTo(mensagemEmail.getDestinatarios()                    .toArray(new String[mensagemEmail.getDestinatarios().size()]));
            FileSystemResource fileSystemResource = new FileSystemResource(mensagemEmail.getAnexo());
            mimeMessageHelper.addAttachment(fileSystemResource.getFilename(), fileSystemResource);
            javaMailSender.send(mimeMessage);
        }catch (Exception e){
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
    }
    public void sendEmailWithTestMessage(MensagemEmail mensagemEmail){
        try {
            MimeMessage mimeMessage = javaMailSender.createMimeMessage();
            MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, "utf-8");
            mimeMessageHelper.setFrom(mensagemEmail.getRemetente());
            mimeMessageHelper.setSubject(mensagemEmail.getAssunto());
            mimeMessageHelper.setText(mensagemEmail.getTexto(), true);
            mimeMessageHelper.setTo(mensagemEmail.getDestinatarios()                    .toArray(new String[mensagemEmail.getDestinatarios().size()]));
            javaMailSender.send(mimeMessage);
        }catch (Exception e){
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
    }
}

Primeiro, deve ser injetado o JavaMailSender que foi instanciado como Bean para uso do Spring. Utilizei dois métodos. O primeiro envia arquivos e o segundo apenas uma mensagem de teste. Para enviar e-mail, utiliza-se a classe MimeMessage. Depois, instancia-se a classe mimeMessageHelper e configura-se tudo baseado em programação funcionário. A única atenção especial que se deve ter é que o setTo trabalha com Arrays. Para o envio de anexo, optei pela classe FileSystemResource. Para enviar o arquivo, utilizei o caminho absoluto. Depois, basta colocar o método addAttachment. Para testar o envio, primeiramente utilizei um controller de API, no caso, uma aplicação que eu já possuía.


import com.mindsim.petroapi.email.model.MensagemEmail;
import com.mindsim.petroapi.services.EmailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("v1/petroapi/enviaremails")
public class EmailController {
    @Autowired
    private EmailService emailService;
    @PostMapping("/mensagemteste")
    public ResponseEntity<?> enviarEmail(@RequestBody MensagemEmail mensagemEmail){
        try{
            emailService.sendEmailWithTestMessage(mensagemEmail);            return new ResponseEntity<>(HttpStatus.OK);
        }catch (Exception e){
            return new ResponseEntity<>(e.getMessage(),HttpStatus.INTERNAL_SERVER_ERROR);        }
    }
    @PostMapping("/enviaranexo")
    public ResponseEntity<?> enviarArquivo(@RequestBody MensagemEmail mensagemEmail){
        try{
            emailService.sendEmailWithFile(mensagemEmail);
            return new ResponseEntity<>(HttpStatus.OK);
        }catch (Exception e){
            return new ResponseEntity<>(e.getMessage(),HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
}


ree

Já no projeto Spring Batch, criei um Job com apenas um Step. Lembrando que isso é o começo de uma aplicação. No geral, aplicações comerciais irão possuir disparadores e tarefas agendadas conforme citado anteriormente. O código abaixo é para o Spring Batch 4, pois se trata de uma aplicação Java 8. Importante reforçar que o Spring Batch 5 já possui uma maneira de escrever código bastante distinta.


import com.eduardondarocha.mindsimapp.model.MensagemEmail;
import com.eduardondarocha.mindsimapp.service.EmailService;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@EnableBatchProcessing
@Configuration
public class BatchConfig {
    @Autowired
    private JobBuilderFactory jobBuilderFactory;
    @Autowired
    private EmailService emailService;
    @Autowired    private StepBuilderFactory stepBuilderFactory;
    @Bean    public Job imprimeOlaJob(){
        return jobBuilderFactory
                .get("imprimeOlaOjb")
                .start(enviaEmailStep())
                .build();
    }
    public Step enviaEmailStep(){
        return stepBuilderFactory
                .get("enviaEmailStep").tasklet(new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
                        System.out.println("Enviando e-mail");
                        MensagemEmail mensagemEmail = MensagemEmail.builder()
                                .texto("E-mail disparado pelo spring batch")
                                .destinatarios(Stream.of("destinatario1@email.com.br","destinatario2@email.com.br").collect(Collectors.toList()))                                   .assunto("Teste Spring Batch de envio de arquivo")
                                .remetente("enrtecnologiaeconhecimento@gmail.com")
                                .anexo("D:/Arquivos_Github/petrorestapi/src/main/java/com/mindsim/petroapi/files/testemindsim.txt")
                                .build();
                        try {
                            emailService.sendEmailWithFile(mensagemEmail);
                        }catch (Exception e){
                            System.out.println(e.getMessage());
                        }
                        return RepeatStatus.FINISHED;
                    }
                }).build();
    }
}

Os links para os projetos nos quais foram utilizados o Spring Starter Email seguem abaixo:

ความคิดเห็น


bottom of page