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!