Recentemente, peguei um caso que começou com uma simples reconfiguração de autenticação DNS e escalou para uma corrupção profunda de estado no subsistema de e-mail. O ticket relatava que mensagens estavam sendo recebidas pelo servidor, mas nunca chegavam à caixa de entrada do cliente.
O que parecia um problema de roteamento básico revelou-se um desvio grave entre a camada de armazenamento (filesystem) e a máquina de estado do serviço IMAP. Abaixo, detalho a autópsia desse incidente.
O problema técnico#
Inicialmente, atuei na regularização da autenticação do domínio (domain.com). O ambiente cPanel estava defasado em suas chamadas de API antigas (/scripts/email_auth), o que me obrigou a invocar diretamente a UAPI e o ZoneEdit via terminal para injetar as chaves DKIM e a política DMARC (v=DMARC1; p=none).
Com o DNS estabilizado, o real problema se manifestou: um e-mail de teste (ID 1vRXMv-00000001G0c-0CLv) foi disparado, o servidor aceitou a conexão SMTP, mas o cliente não enxergava a mensagem via IMAP ou Webmail. O e-mail virou um fantasma.
A estrutura maildir no filesystem#
Para entender como a desincronia ocorre, precisamos visualizar a anatomia padrão de um diretório Maildir. No Dovecot, cada caixa de e-mail do usuário possui a seguinte árvore:
/home/user/mail/domain.com/user/
├── cur/ # Mensagens já lidas e processadas pelo cliente
├── new/ # Mensagens novas entregues, aguardando leitura
├── tmp/ # Arquivos temporários durante a escrita de entrega
├── .Sent/ # Subpasta: Mensagens Enviadas
│ ├── cur/
│ ├── new/
│ └── tmp/
├── .Drafts/ # Subpasta: Rascunhos
├── .Trash/ # Subpasta: Lixeira
├── dovecot.index # Cache binário rápido de cabeçalhos e flags
├── dovecot.index.log # Log transacional de alterações do índice
├── dovecot-uidlist # Mapeamento crítico de nomes físicos ↔ UIDs IMAP
└── subscriptions # Arquivo texto com pastas assinadas pelo usuário
Rastreando o inode#
A primeira etapa foi rastrear o envelope no MTA. O log de entrega do Exim (/var/log/exim_mainlog) mostrou um fluxo impecável e detalhado:
2026-06-07 12:05:01 [email protected] R=virtual_user T=dovecot_virtual_delivery U=user C="250 2.0.0 <[email protected]> sNJzJ6b0MmkR7QMAgRW0Lg Saved" QT=1.234s DT=0.567s
O status Saved provava que o Exim fez o handoff com sucesso para o processo LMTP do Dovecot. O MTA não estava dropando o pacote nem enfrentando loops de roteamento. O problema estava do lado do MDA (Mail Delivery Agent).
Ao inspecionar o Maildir da usuária, um grep pelo ID da mensagem falhou silenciosamente. Fui checar o diretório físico da fila new/ usando um ls -latr. O arquivo estava lá: o inode havia sido alocado às 12:05 sob o nome 1781476345.M965412P23485.servidor.domain.com,S=4035,W=4112.
Por que o grep falhou se o arquivo existia? Ao dar um cat no arquivo, o terminal exibiu lixo binário. O servidor estava rodando o Dovecot com o plugin Zlib ativado. O grep padrão opera em plain text e bateu no muro da compressão. Usando um zcat, consegui ler o buffer descomprimido e ver os cabeçalhos SMTP intactos. O arquivo estava perfeito no disco, mas o daemon IMAP estava cego para ele.
Rastreabilidade de código: a máquina de estado do Dovecot#
O fluxo de falha ocorreu na interface entre o VFS (Virtual File System) e o indexador do Dovecot. Quando o LMTP do Dovecot recebe o stream do Exim, ele invoca a biblioteca Zlib para comprimir o payload antes de acionar a syscall de escrita (write()) no disco.
Após o flush no disco, o Dovecot precisa atualizar o arquivo dovecot-uidlist, que mapeia o nome físico do arquivo para um UID sequencial padrão IMAP, e o arquivo dovecot.index. Uma race condition, uma queda abrupta do daemon ou um I/O lock corrompeu essa estrutura. O arquivo foi gravado, mas a transação de metadados falhou. O daemon se recusava a apresentar qualquer arquivo na pasta new/ que não estivesse rigidamente mapeado no seu uidlist.
Diagnóstico forense no servidor#
Para comprovar a desincronia e mapear a causa raiz, executei os seguintes passos de auditoria técnica:
1. Verificar mail_location e caminhos físicos#
Primeiro, verifique onde o Dovecot está configurado para ler e gravar as caixas:
doveconf -n | grep mail_location
# Saída esperada: mail_location = maildir:/home/%d/%n/mail:LAYOUT=fs
Em seguida, valide se o diretório existe fisicamente com o dono correto:
ls -la /home/user/mail/domain.com/user/
2. Auditar logs do Dovecot e LMTP#
Examine os logs específicos do subsistema de correio para capturar falhas de leitura ou escrita de índice:
# Monitorar logs gerais de mail
tail -f /var/log/maillog | grep -E -i "dovecot|lmtp|uidlist|index"
# Ou logs direcionados (dependendo da configuração do sistema)
tail -f /var/log/dovecot.log | grep -i error
3. Verificar status do plugin zlib#
Para checar se a compressão em tempo real está ativa:
# Filtrar configurações ativas de plugin
doveconf -n | grep -A5 plugin
# Verificar especificamente o plugin zlib
doveconf -n | grep -i zlib
4. Verificar espaço em disco e quotas#
Se a partição estiver cheia ou a quota do usuário de e-mail/cPanel estourar durante o processo de gravação do LMTP, os índices do Dovecot serão gerados de forma corrompida.
# Verificar espaço em disco
df -h /home
# Verificar quota do usuário no sistema
repquota -a | grep user
# Verificar uso de disco da pasta de mail do usuário
du -sh /home/user/mail/
# Buscar arquivos de 0 bytes (indicador clássico de falha de gravação de índice ou uidlist)
find /home/user/mail/ -size 0 -type f
5. Verificar versão e configuração completa do Dovecot#
Identifique se a versão rodando possui vulnerabilidades de indexação ou se há pacotes de atualização do Dovecot pendentes:
# Versão do Dovecot
doveadm --version
# Verificar se há atualizações do Dovecot disponíveis
yum check-update dovecot # Sistemas baseados em RHEL/CentOS
apt list --upgradable | grep dovecot # Sistemas baseados em Debian/Ubuntu
# Verificar dump de configuração não padrão ativa
doveconf -n | head -50
6. Verificar conexões ativas e estado do IMAP IDLE#
Sessões ativas via IMAP IDLE podem prender os arquivos de metadados no disco e inviabilizar a reindexação adequada das pastas.
# Verificar se IDLE está configurado
doveconf -n | grep -i "idle"
# Verificar conexões e usuários ativos em tempo real
doveadm who
# Listar de forma detalhada e em linha única as sessões travadas
doveadm who -1
7. Verificar TLS/SSL no Dovecot#
Problemas de handshake TLS podem mascarar erros de sincronização nas conexões IMAP dos clientes.
# Verificar configuração SSL/TLS ativa
doveconf -n | grep -i "ssl"
# Verificar permissões e presença dos certificados
ls -la /etc/dovecot/ssl/ 2>/dev/null
# Confirmar se SSL está habilitado globalmente
doveconf -n | grep "ssl = yes"
8. Mapear escopo do problema (verificação multi-contas)#
Verifique se a desincronia de índices é um problema isolado ou sistêmico no servidor:
# Verificar se há outras contas com erros em dovecot-uidlist
find /home/*/mail -name "dovecot-uidlist" -exec grep -l "error" {} \; 2>/dev/null
# Buscar índices de e-mail vazios em outras contas do servidor
find /home/*/mail -name "dovecot.index" -size 0 -type f 2>/dev/null
# Consultar recursivamente o status da Inbox de todos os usuários cadastrados
doveadm user "*" | while read user; do
doveadm mailbox status -u "$user" INBOX 2>&1 | grep -i "error" && echo "Problema na conta: $user"
done
Hipóteses descartadas#
Antes de partir para a manipulação de disco, isolei as variáveis:
- Roteamento Local vs Remoto: Verifiquei o
/etc/localdomains. O domínio estava corretamente alocado localmente; não havia bypass no Exim. - Ação de MUA / POP3 Agressivo: Vasculhei os logs buscando sessões POP3 que pudessem ter baixado e enviado o comando
DELEmilissegundos após a entrega. Negativo. - Formato mdbox vs Maildir: Confirmei a estrutura dos diretórios (
cur,new,tmp). Estávamos lidando com o formato Maildir clássico, não com blocos binários mdbox. - Corrupção leve de Índice: Tentei renomear o arquivo via
mvpara invalidar a leitura de tamanho (,S=...) e forçar o daemon a tratá-lo como um novo evento de I/O. Não surtiu efeito.
Opções de recuperação escalonadas (do simples ao nuclear)#
Diante da falha técnica, as ações de mitigação devem seguir uma ordem lógica de severidade, evitando a perda de dados.
Nível 1: Resync e desconexão de sessões ativas#
Antes de intervir fisicamente, remova todas as conexões presas da usuária e force a sincronização lógica da inbox:
# Desconecta sessões IMAP/POP3 ativas do usuário
doveadm kick -u [email protected]
# Sincroniza a Inbox principal
doveadm force-resync -u [email protected] INBOX
Nível 2: Reindexação forçada das pastas#
Se o resync simples falhar, obrigue o Dovecot a invalidar e reconstruir os índices para todas as pastas da conta:
# Força a reconstrução de índices da Inbox
doveadm index -u [email protected] INBOX
# Sincroniza todas as pastas recursivamente
doveadm force-resync -u [email protected] "*"
Nível 3: Recuperação de mailbox nativa#
Invoque a rotina interna do Dovecot de reparação de caixas Maildir/Mdbox:
doveadm mailbox recover -u [email protected]
Nível 4: Reconstrução manual de índices (sem deletar a conta)#
Se as ferramentas automáticas do doveadm falharem em reestabelecer o UID, você pode limpar os arquivos físicos de metadados manualmente.
# 1. Parar temporariamente as conexões do usuário
doveadm kick -u [email protected]
# 2. OBRIGATÓRIO: Backup preventivo dos arquivos de índice específicos antes da remoção
BACKUP_IDX="/root/dovecot-index-backup-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$BACKUP_IDX"
cp -a /home/user/mail/domain.com/user/dovecot.index* "$BACKUP_IDX/"
cp -a /home/user/mail/domain.com/user/dovecot-uidlist "$BACKUP_IDX/" 2>/dev/null
echo "Backup de índices salvo em: $BACKUP_IDX"
# 3. OBRIGATÓRIO: Verificar a integridade do backup de índices
ls -la "$BACKUP_IDX/"
du -sh "$BACKUP_IDX/"
# Garantir que os arquivos críticos de cache foram copiados com tamanho maior que zero
# 4. Remover arquivos de índice e controle corrompidos (NUNCA os diretórios cur/new/tmp!)
find /home/user/mail/domain.com/user/ -maxdepth 1 -name "dovecot.index*" -delete
rm -f /home/user/mail/domain.com/user/dovecot-uidlist
# 5. Forçar resync para gerar um novo UIDlist e índices limpos
doveadm force-resync -u [email protected] "*"
Nível 5: Opção nuclear controlada (expurgo de estrutura)#
Se a reindexação de baixo nível falhar por corrupções no banco de dados do próprio painel (cPanel), o expurgo lógico da conta se faz necessário:
# 1. ANTES de tudo: Realizar backup completo dos e-mails e logs de auditoria
BACKUP_DIR="/root/mail-backup-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$BACKUP_DIR"
cp -a /home/user/mail/domain.com/user/ "$BACKUP_DIR/"
cp /var/log/exim_mainlog "$BACKUP_DIR/"
cp /var/log/maillog "$BACKUP_DIR/"
echo "Backup emergencial criado em: $BACKUP_DIR"
# 2. OBRIGATÓRIO: Verificar a integridade do backup do Maildir gerado
echo "=== Validando Integridade do Backup ==="
ls -la "$BACKUP_DIR/user/"
du -sh "$BACKUP_DIR/user/"
# Verificar se todos os 6 diretórios de e-mail críticos estão presentes
ls -d "$BACKUP_DIR/user"/{cur,new,tmp,.Sent,.Drafts,.Trash} 2>/dev/null | wc -l
# Deve retornar 6. Se retornar menos, o backup está incompleto!
# 3. Mover a pasta antiga para fora do path do daemon
mv /home/user/mail/domain.com/user /home/user/mail/domain.com/user_OLD_BKP
# 4. Deletar a conta logicamente via UAPI para limpar lixo no banco do painel
uapi Email delete_pop user=user domain=domain.com
# 5. Recriar a conta limpa via UAPI
uapi Email add_pop user=user domain=domain.com password='MinhaSenhaSeguraAqui'
# 6. OBRIGATÓRIO: Verificar se a conta foi devidamente recriada e registrada no painel e no Dovecot
echo "=== Verificando Recriação da Conta ==="
ls -la /home/user/mail/domain.com/user/
uapi Email list_pop user=user domain=domain.com
doveadm user [email protected]
# 7. Enxertar cirurgicamente os e-mails (apenas pastas cur/new/tmp e subpastas de sistema)
# Ignoramos arquivos como dovecot.index e dovecot-uidlist para não trazer corrupção de volta
cp -r /home/user/mail/domain.com/user_OLD_BKP/{cur,new,tmp,.Sent,.Drafts,.Trash} /home/user/mail/domain.com/user/
# 8. Corrigir permissões e ownership (Essencial para o Dovecot poder ler)
chown -R user:user /home/user/mail/domain.com/user/
find /home/user/mail/domain.com/user/ -type d -exec chmod 751 {} \;
find /home/user/mail/domain.com/user/ -type f -exec chmod 640 {} \;
# 9. OBRIGATÓRIO: Verificar se as permissões e o ownership foram aplicados corretamente
echo "=== Verificando Permissões Pós-Chown ==="
# Confirmar owner e group (deve ser user:user)
ls -la /home/user/mail/domain.com/user/
# Validar se diretórios têm permissão 751
find /home/user/mail/domain.com/user/ -type d -exec stat -c "%a %n" {} \; | head -n 10
# Validar se arquivos têm permissão 640
find /home/user/mail/domain.com/user/ -type f -exec stat -c "%a %n" {} \; | head -n 10
# 10. Forçar sincronização lógica para mapear os novos arquivos aos índices estéreis
doveadm force-resync -u [email protected] "*"
Significado das permissões recomendadas: Diretórios (751 -rwxr-x--x): Permite leitura, escrita e execução ao dono do sistema (cPanel user); leitura e execução ao grupo (correio/dovecot); e apenas execução a terceiros para acessar os subdiretórios. Arquivos (640 -rw-r-----): Permite leitura e escrita ao dono, apenas leitura ao grupo de correio, e nega completamente o acesso a terceiros.
Validação pós-correção (pós-fix)#
Após aplicar a solução, verifique se a sincronização foi bem-sucedida e se novos e-mails entram normalmente no fluxo:
# 1. Pesquisar e-mails via CLI na Inbox e confirmar se o 'fantasma' aparece na lista
doveadm search -u [email protected] INBOX ALL
# 2. Verificar status atual da caixa
doveadm mailbox status -u [email protected] INBOX
# 3. Disparar e-mail de teste e validar logs em tempo real
tail -n 20 /var/log/maillog | grep -i "error\|fail"
Prevenção e monitoramento proativo#
Para mitigar ocorrências similares no futuro, implemente as seguintes boas práticas de sysadmin:
- Monitoramento de Erros de UID: Crie um cron job diário para rodar checagens e alertar sobre erros de metadados:
doveadm mailbox status -u ALL USERS "uidlist" 2>&1 | grep -i error
- Desligamento Graceful e No-Break (UPS): Quedas abruptas de energia causam escritas de índice corrompidas. Certifique-se de que a UPS envie sinais de
powerfailpara fazer o shutdown limpo do Dovecot. - Controle de Alocação de Disco: E-mails fantasmas acontecem quando a partição ou a cota (
quota) atinge 100% durante transações de escrita do LMTP. Implemente alertas ativos de quota a 90%.
Fluxo de decisão: recuperação de email#
Checklist de recuperação#
Checklist: email fantasma - recuperação Dovecot#
1. Diagnóstico e triagem inicial#
- [ ] Espaço em Disco: Verificar espaço livre com
df -he cotas de usuário comrepquota. - [ ] Logs do MTA: Buscar o ID de mensagem nos logs do Exim:
grep "[email protected]" /var/log/exim_mainlog. - [ ] Logs do MDA: Investigar logs do Dovecot e erros de IMAP/LMTP:
tail -n 100 /var/log/maillog | grep dovecot. - [ ] Validação Física: Listar conteúdo na fila
/home/user/mail/domain.com/user/new/e verificar arquivos de 0 bytes. - [ ] Configurações Gerais: Validar versão (
doveadm --version), configurações ativas (doveconf -n), suporte a TLS e sessões IMAP IDLE. - [ ] Zlib: Checar suporte à compressão e avaliar necessidade conforme o tipo de armazenamento.
- [ ] Escopo/Raio de Ação: Realizar varredura no servidor para checar se outras contas exibem erros de uidlist ou índices.
2. Nível 1 ao 3 (sincronização & reparação lógica)#
- [ ] Kick: Desconectar sessões IMAP/POP3 pendentes (
doveadm kick). - [ ] Resync: Rodar sincronização forçada (
doveadm force-resync -u user@domain INBOX). - [ ] Reindex: Forçar a reconstrução lógica de índices (
doveadm indexedoveadm force-resync -u user@domain "*"). - [ ] Recover: Executar a reestruturação interna nativa (
doveadm mailbox recover).
3. Nível 4 (reindexação manual)#
- [ ] Kick: Desconectar sessões do usuário.
- [ ] Backup dos Índices: Realizar cópia preventiva de
dovecot.index*edovecot-uidlistpara/root/dovecot-index-backup-.... - [ ] Integridade do Backup: Verificar se os arquivos de índices copiados foram salvos e têm tamanho maior que zero.
- [ ] Expurgo dos Índices: Deletar arquivos de índice físico e
dovecot-uidlist(preservandocur,new,tmp). - [ ] Force-Resync: Rodar sincronização completa para regerar os arquivos.
4. Nível 5 (reconstrução nuclear)#
- [ ] Backup Completo: Criar backup emergencial de toda a mailbox (
/home/user/mail/domain.com/user/) e logs de e-mail. - [ ] Integridade do Backup: Checar permissões, presença das 6 pastas críticas (
cur,new,tmp,.Sent,.Drafts,.Trash) e tamanho do backup. - [ ] Quarentena: Mover a pasta da conta afetada para um diretório temporário fora do path ativo.
- [ ] UAPI Expurgo: Excluir a conta logicamente via UAPI (
uapi Email delete_pop). - [ ] UAPI Recriação: Recriar a conta limpa via UAPI (
uapi Email add_pop). - [ ] Validação da Recriação: Testar se o banco do painel atualizou e o Dovecot reconhece a nova conta (
doveadm user). - [ ] Restauração Cirúrgica: Copiar apenas as 6 pastas de e-mail (
cur,new,tmp, etc.) do backup para a nova estrutura (ignorando índices antigos). - [ ] Permissões: Aplicar ownership
user:user, diretórios751e arquivos640. - [ ] Auditoria de Permissões: Verificar recursivamente os atributos aplicados de ownership e permissões do filesystem.
- [ ] Force-Resync: Executar sincronização final e testar o fluxo de envio/recebimento de e-mails.
- [ ] Monitoramento: Acompanhar o comportamento da caixa e o log do Dovecot pelas próximas 24 horas.
Este artigo foi útil?
Deixe uma reação rápida para apoiar o conteúdo:
Este post está licenciado sob CC BY-NC.



Comentários
Participe da discussão abaixo.
0 comentários