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.
// 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:
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.
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
.
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.
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
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: 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! :)
Oldest comments (2)
Excelente. Bem interessante vou salvar aqui.
Obrigada, Gabriel!