Surgiu aqui na empresa a necessidade de automatizar a leitura da caixa de entrada, de tempos em tempos, de um endereço XPTO e que apenas os novos e-mails fossem processados.
O foco deste artigo é mostrar como eu fiz a leitura da caixa de entrada usando JavaMail. O projeto completo está disponível no meu GitHub no meu GitHub e explicarei em artigos futuros as outras tecnologias envolvidas no projeto.
Estrutura do projeto final
Antes de irmos direto ao assunto deste artigo, queria explicar como ficou o projeto final.
O projeto final ficou com a estrutura de pacotes acima, mas não comecei o projeto assim não! Primeiro, criei uma classe de serviço para testar a funcionalidade e só depois de pronto e minimamente testado, fiz a organização de código (tentando colocar em prática os ensinamentos do Uncle Bob).
Considerei como um Util a classe que faz a leitura dos e-mails. Criei um service para incluir a annotation de agendamento do Spring. No pacote com.example.emailverifier.model.vo
coloquei um Bean para retornar objetos do tipo EmailVO com o assunto, corpo do e-mail e endereço de quem enviou o e-mail. No pacote com.example.emailverifier.configuration
, criei uma classe que representa as properties que o Spring lê ao iniciar a aplicação. Essas properties configurei como variáveis de ambiente no Intellij e são o usuário e senha de acesso à caixa de entrada que deve ser lida.
Dependências
Abaixo, vão algumas dependências que incluí para a leitura de mensagens.
gradle
// JavaMail
implementation group: 'javax.mail', name: 'mail', version: '1.4.1'
// Lombok
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
Código fonte
No meu caso específico, trabalhei com o protocolo IMAP que é responsável pelo recebimento dos e-mails. Usei ele por causa do requisito de ler somente e-mails novos, então teria que marcar quem foi processado como lido. POP3 não dispõe desta funcionalidade. Tem um artigo interessante que explica a diferença entre os protocolos IMAP, POP3 e SMTP aqui.
Classe EmailVerifierUtil.java
No pacote com.example.emailverifier.utils
, criei a classe EmailVerifierUtils.java
que implementa a leitura da caixa de entrada a partir do método público getNewMessages()
.
Este método possui 3 linhas importantes:
java
connectEmail();
inbox = getFolder(FOLDER_INBOX);
List<EmailVO> emailVOS = readMessagesFromFolder(inbox);
A primeira linha, chama o método connectEmail
que faz exatamente isso: obtém a instância padrão de uma sessão de e-mail a partir de algumas propriedades (que no meu caso, não tem); cria uma Store
a partir da sessão, de acordo com o protocolo IMAP e; finalmente faz a conexão com essa Store passando as credenciais, host e porta.
java
private void connectEmail() throws MessagingException {
Session emailSession = Session.getDefaultInstance(new Properties());
imapStore = (IMAPStore) emailSession.getStore(IMAP_PROTOCOL);
imapStore.connect(HOST, PORT, emailCredentials.getUsername(), emailCredentials.getPassword());
}
O método getFolder
recebe o nome da pasta que queremos ler e usa a instância Store criada anteriormente para obter uma instância de Folder
e abrir no modo desejado: READ_WRITE
ou READ_ONLY
.
java
private Folder getFolder(String folderName) throws MessagingException {
Folder inbox = imapStore.getFolder(folderName);
if (inbox != null) inbox.open(Folder.READ_WRITE);
return inbox;
}
Com e-mail conetado e pasta prontinha para ser lida, vamos para o método readMessagesFromFolder
ler as mensagens. Passamos a instância de Folder
, checamos se ela existe e depois obtemos as mensagens não lidas por meio do método getUnseenMessages
que retorna um array de objetos Message. Após isso, percorremos este array e criamos objetos do tipo EmailVO para retornar ao service bonitinho: com o endereço remetente, assunto e conteúdo do e-mail. É neste ponto que adicionamos uma flag à mensagem para que ela seja considerada lida.
java
private List<EmailVO> readMessagesFromFolder(Folder folder) throws MessagingException, IOException {
if (folder == null) {
logger.info("No folder found.");
return null;
}
Message[] messages = getUnseenMessages(folder);
if (messages.length == 0) logger.info("No messages found.");
List<EmailVO> emails = new ArrayList<>();
for (Message message : messages) {
Address[] from = message.getFrom();
emails.add(EmailVO.builder()
.from(((InternetAddress) from[0]).getAddress())
.subject(message.getSubject())
.content(message.getContent().toString())
.build());
message.setFlag(Flags.Flag.SEEN, true);
}
return emails;
}
No finally
do método getNewMessages
, encerramos as conexões com a pasta Inbox e com a caixa de entrada.
ATENÇÃO! Para executar o projeto, precisamos configurar as variáveis de ambiente email.username
e email.password
com as credenciais do e-mail.
Rodando o projeto via Intellij, temos sucesso! :D
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _{% raw %}` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.6.1)
2021-12-01 18:11:12.869 INFO 87412 --- [ main] c.e.e.EmailVerifierApplication : Starting EmailVerifierApplication using Java 15.0.2 on leila-note with PID 87412 (/home/leila/projetos/pocs/email-verifier/build/classes/java/main started by leila in /home/leila/projetos/pocs/email-verifier)
2021-12-01 18:11:12.870 INFO 87412 --- [ main] c.e.e.EmailVerifierApplication : No active profile set, falling back to default profiles: default
2021-12-01 18:11:13.296 INFO 87412 --- [ main] c.e.e.EmailVerifierApplication : Started EmailVerifierApplication in 0.747 seconds (JVM running for 0.995)
2021-12-01 18:11:30.001 INFO 87412 --- [ scheduling-1] c.e.e.utils.EmailVerifierUtil : Verifying new messages inbox...
2021-12-01 18:11:33.341 INFO 87412 --- [ scheduling-1] c.e.e.utils.EmailVerifierUtil : No messages found.
2021-12-01 18:11:33.341 INFO 87412 --- [ scheduling-1] c.e.e.utils.EmailVerifierUtil : Success on verifying new messages inbox!
2021-12-01 18:11:33.628 INFO 87412 --- [ scheduling-1] c.e.emailverifier.service.EmailService : Found 0 new message(s)!
2021-12-01 18:12:00.000 INFO 87412 --- [ scheduling-1] c.e.e.utils.EmailVerifierUtil : Verifying new messages inbox...
2021-12-01 18:12:01.930 INFO 87412 --- [ scheduling-1] c.e.e.utils.EmailVerifierUtil : Success on verifying new messages inbox!
2021-12-01 18:12:02.213 INFO 87412 --- [ scheduling-1] c.e.emailverifier.service.EmailService : Found 1 new message(s)!
```
Bem tranquilo, né? Só que não! XD
Percorri alguns sites, tutoriais, posts do Stackoverflow para chegar neste resultado que FUNCIONA.
Portanto, caso você também precise fazer algo parecido com isso, **SALVE** este artigo, fique à vontade para copiar, modificar e melhorar o código aqui apresentado.
Como falei no início do artigo, farei mais alguns explicando as tecnologias que utilizei no projeto, tais como o agendamento de tarefas com Spring Boot e Junit com Mockito para os testes.
Curtiu?
O que poderia melhorar?
Tem algum termo/assunto que deseja ler por aqui? Me conta!
Até a próxima! :)
Top comments (2)
Excelente. Bem interessante vou salvar aqui.
Obrigada, Gabriel!