Enviando (e também disparando) e-mails em Java
- 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);
}
}
}

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:
ความคิดเห็น