DEV Community

Leila Oliveira
Leila Oliveira

Posted on

Leitura de e-mails com JavaMail

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

Estrutura de pacotes do projeto

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'

Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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());
    }
Enter fullscreen mode Exit fullscreen mode

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;
    }
Enter fullscreen mode Exit fullscreen mode

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;
    }
Enter fullscreen mode Exit fullscreen mode

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)!
Enter fullscreen mode Exit fullscreen mode

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)

Collapse
 
gabrielsantosba profile image
Gabriel Bahia.

Excelente. Bem interessante vou salvar aqui.

Collapse
 
leilasoliveira profile image
Leila Oliveira

Obrigada, Gabriel!