Coleta IMAP do MVP de e-mails
Esta etapa implementa a leitura somente leitura das contas IMAP cadastradas em email_accounts, com persistência idempotente em email_messages.
Biblioteca usada
webklex/laravel-imap
Dependências e extensões
- PHP 8.2+
- Laravel 12
webklex/laravel-imapwebklex/php-imap- Extensões recomendadas:
mbstringopenssl
Estratégia técnica
- O client é montado em runtime a partir de
EmailAccount. - Não existe conta fixa em
config/imap.php. - A conexão sempre usa modo somente leitura.
- A coleta usa
FT_PEEKou equivalente para evitar marcar mensagens como lidas. - O fluxo não executa ações destrutivas no servidor IMAP.
Services
App\Services\Email\ImapClientFactoryApp\Services\Email\EmailConnectionServiceApp\Services\Email\EmailFolderSyncServiceApp\Services\Email\EmailInboxSyncServiceApp\Services\Email\EmailMessagePersistenceServiceApp\Services\Email\EmailSyncAuditService
Comandos Artisan
php artisan email:test-connection {accountId}php artisan email:sync-folders {accountId}php artisan email:sync-inbox {accountId} {--limit=50}php artisan email:sync {accountId} {--limit=50} {--queue}
Fluxo de teste de conexão
- Localizar a conta.
- Validar
active, host, porta, usuário e senha. - Criar o client IMAP dinamicamente.
- Conectar.
- Desconectar.
- Registrar auditoria sanitizada.
Sincronização de pastas
- Conectar uma vez por conta.
- Listar pastas remotas.
- Normalizar
nameedisplay_name. - Criar ou atualizar
email_folders. - Preservar
sync_enabledquando a pasta já existir. - Atualizar
uid_validityelast_sync_at. - Não apagar pastas locais nesta issue.
Coleta da INBOX
- Coletar somente
INBOX. - Usar
last_uid + 1quando existir cursor. - Se não houver cursor, buscar os
--limitmais recentes. - Persistir mensagens com idempotência por
email_account_id + folder + message_uid. - Atualizar
last_uidelast_sync_atsomente após o lote concluir com sucesso. - Não baixar anexos binários.
- Registrar apenas metadados dos anexos quando a biblioteca expuser isso sem download.
Idempotência
- A barreira principal já está no banco.
- O processo também usa
updateOrCreatecom tratamento de violação de chave única. - Rodar a sincronização duas vezes não deve duplicar mensagens.
Auditoria sanitizada
Eventos registrados:
email_connection_testedemail_connection_failedemail_folders_syncedemail_inbox_syncedemail_sync_failed
Metadados permitidos:
email_account_idemail_addressimap_hostimap_portfolderphaseerror_classsafe_messagemessages_seenmessages_createdmessages_skippedlast_uid
Risco de uid_validity
uid_validityé tratado como estado operacional.- Se mudar, a sincronização registra auditoria e pode reiniciar o cursor da INBOX.
- O risco residual é que o servidor remapeie UIDs e a conta precise de reprocessamento manual.
Execução manual
- Teste de conexão:
php artisan email:test-connection 1
- Sincronizar pastas:
php artisan email:sync-folders 1
- Sincronizar INBOX:
php artisan email:sync-inbox 1 --limit=50
- Sincronizar tudo:
php artisan email:sync 1 --limit=50
- Despachar para fila:
php artisan email:sync 1 --limit=50 --queue
O que fica para as próximas issues
- Issue #15: classificação, resumo e sugestões com IA.
- Issue #16: telas e revisão humana.
- Issue #17: SMTP e envio de respostas aprovadas.