O módulo imaplib implementa um cliente IMAP na biblioteca padrão do Python. Ele permite listar caixas, pesquisar mensagens, buscar headers e corpos, copiar, mover por operações compatíveis, alterar flags e acompanhar novas mensagens. É útil para automações de suporte, processamento de anexos, arquivamento e integrações corporativas.
IMAP trabalha diretamente com uma caixa real. Uma chamada errada pode marcar mensagens como lidas, adicionar \Deleted ou removê-las com EXPUNGE. Comece com seleção somente leitura, use UIDs e teste em uma conta isolada.
Conexão segura com IMAP4_SSL
import imaplib
import ssl
contexto = ssl.create_default_context()
with imaplib.IMAP4_SSL(
"imap.example.com",
port=993,
ssl_context=contexto,
timeout=15,
) as cliente:
cliente.login("usuario@example.com", "senha")
print(cliente.noop())
A documentação informa que o contexto SSL padrão interno pode criptografar sem verificar certificado e hostname. Passe explicitamente ssl.create_default_context(). Não use IMAP simples na porta 143 com senha antes de STARTTLS.
Para certificados corporativos e versões mínimas, consulte ssl no Python.
Credenciais e autenticação
Não fixe senhas no código. Use variáveis de ambiente, gerenciador de segredos ou OAuth quando o provedor exigir. O método authenticate() permite mecanismos SASL suportados pelo servidor.
Alguns provedores desativam login por senha. Confirme capabilities e documentação do serviço. Nunca imprima tokens, senha ou respostas completas de autenticação.
Verificando capabilities
print(cliente.capabilities)
Capabilities indicam recursos como IMAP4REV1, IDLE, UIDPLUS, MOVE ou mecanismos de autenticação. Não presuma suporte universal. Implemente fallback ou recuse a operação quando o recurso for obrigatório.
Listando caixas
tipo, linhas = cliente.list()
if tipo != "OK":
raise RuntimeError("não foi possível listar caixas")
for linha in linhas or []:
print(linha.decode("utf-8", errors="replace"))
Os nomes podem usar codificação IMAP específica e separadores diferentes. Evite extrair campos por split() ingênuo. Bibliotecas de alto nível podem ser melhores quando você precisa de compatibilidade ampla com nomes internacionais.
Selecionando INBOX em modo somente leitura
tipo, dados = cliente.select("INBOX", readonly=True)
if tipo != "OK":
raise RuntimeError("falha ao abrir INBOX")
quantidade = int(dados[0])
print("mensagens:", quantidade)
readonly=True reduz o risco de alterações. Para marcar, mover ou excluir, abra conscientemente com escrita e revalide a caixa.
Use UIDs, não números de sequência
Números de mensagem mudam quando a caixa muda, especialmente após EXPUNGE. UIDs são mais estáveis dentro da caixa.
tipo, dados = cliente.uid("search", None, "ALL")
if tipo != "OK":
raise RuntimeError("busca falhou")
uids = dados[0].split()
print(uids[-10:])
UIDs não são identificadores globais eternos. Uma caixa recriada pode ter outro UIDVALIDITY. Sistemas de sincronização devem armazenar mailbox, UIDVALIDITY e UID.
Buscas IMAP
tipo, dados = cliente.uid(
"search",
None,
"UNSEEN",
"SINCE",
"01-Jul-2026",
)
Critérios são interpretados pelo servidor. Datas usam formato IMAP e não incluem hora. Para assuntos ou remetentes, cuide de charset e quoting. Não monte critérios diretamente a partir de entrada não confiável sem validação.
Lendo headers sem marcar como lida
tipo, dados = cliente.uid(
"fetch",
uid,
"(BODY.PEEK[HEADER.FIELDS (FROM TO SUBJECT DATE MESSAGE-ID)])",
)
BODY.PEEK busca dados sem adicionar \Seen em servidores compatíveis. BODY[] pode marcar a mensagem como lida. Teste o comportamento do provedor.
Interpretando o retorno de fetch
Uma resposta FETCH pode conter dados adicionais e respostas não solicitadas. A documentação alerta para não depender apenas de data[0][1]. Inspecione tuplas e bytes.
def literais_fetch(dados):
for item in dados or []:
if isinstance(item, tuple) and len(item) == 2:
cabecalho, literal = item
if isinstance(literal, bytes):
yield cabecalho, literal
Limite o tamanho solicitado. Para mensagens grandes, busque apenas partes necessárias ou use partial() quando o servidor suportar.
Parseando uma mensagem
from email import policy
from email.parser import BytesParser
mensagem = BytesParser(policy=policy.default).parsebytes(raw_email)
print(mensagem.get("Subject"))
print(mensagem.get("From"))
Headers e corpos são dados não confiáveis. Não renderize HTML de e-mail sem sanitização. Nomes de anexos não devem virar caminhos locais diretamente.
Extraindo texto com limites
def partes_texto(mensagem, limite=1_000_000):
total = 0
for parte in mensagem.walk():
if parte.get_content_maintype() == "multipart":
continue
if parte.get_content_disposition() == "attachment":
continue
conteudo = parte.get_payload(decode=True) or b""
total += len(conteudo)
if total > limite:
raise ValueError("mensagem grande demais")
yield parte.get_content_type(), conteudo
Decodifique usando charset declarado com fallback seguro. O guia de codecs no Python ajuda a tratar erros de encoding.
Salvando anexos com segurança
Gere um nome interno, aplique limite de tamanho, valide tipo real e armazene fora de diretórios executáveis. O header de filename pode conter path traversal, caracteres de controle ou nomes repetidos.
Use tempfile no Python durante validação e hashlib no Python para integridade e deduplicação.
Flags
Flags comuns incluem \Seen, \Answered, \Flagged, \Deleted e \Draft. Use UID STORE e operações silenciosas quando não precisar da resposta completa.
cliente.uid(
"store",
uid,
"+FLAGS.SILENT",
r"(\Seen)",
)
Antes de alterar, confirme que o UID pertence à mensagem esperada. Em automações, registre a decisão de domínio, não o conteúdo sensível.
Exclusão em duas etapas
Normalmente, excluir significa adicionar \Deleted e depois executar EXPUNGE. EXPUNGE pode remover todas as mensagens marcadas na caixa, inclusive por outro cliente.
cliente.uid("store", uid, "+FLAGS.SILENT", r"(\Deleted)")
# não chame expunge automaticamente sem política explícita
Quando disponível, extensões UIDPLUS ou MOVE oferecem operações mais previsíveis. Para encerrar sem expurgar, unselect() libera a caixa. close() pode remover mensagens marcadas em uma caixa gravável.
Copiar e mover
copy() copia mensagens. Um movimento legado costuma ser COPY, marcação \Deleted e EXPUNGE, o que exige cuidado. Se o servidor anuncia MOVE, use a extensão via uid("MOVE", ...) e teste o resultado.
IDLE no Python 3.14
idle() cria um context manager iterável que recebe notificações como EXISTS. Defina duração para evitar timeouts do servidor.
with cliente.idle(duration=29 * 60) as idler:
for tipo, dados in idler:
if tipo == "EXISTS":
print("a caixa mudou", dados)
Notificação não substitui busca. Ao receber evento, execute uma sincronização por UID. Reconecte com backoff quando a conexão cair.
Timeout total e reconexão
O parâmetro timeout cobre a abertura da conexão, mas tarefas longas precisam de deadline total e política de reconexão. IMAP4.abort normalmente exige fechar e criar outra instância.
Não repita operações de escrita sem saber se o servidor as executou. Uma queda depois de STORE pode deixar estado incerto.
Tratando respostas
A maioria dos métodos retorna (tipo, dados), onde tipo costuma ser OK, NO ou BAD. Não considere ausência de exceção como sucesso.
tipo, dados = cliente.uid("search", None, "ALL")
if tipo != "OK":
detalhe = dados[0] if dados else b"sem detalhe"
raise RuntimeError(f"IMAP retornou {tipo}: {detalhe!r}")
Logs e privacidade
Não ative imaplib.Debug em produção. O protocolo pode revelar comandos, endereços, subjects e identificadores. Registre apenas caixa lógica, operação, duração, quantidade e um ID de correlação.
Testes recomendados
Teste certificado inválido, login rejeitado, caixa ausente, readonly, UIDs, UIDVALIDITY, mensagens multipart, charset inválido, anexos grandes, flags, reconexão, IDLE, resposta FETCH adicional e proteção contra EXPUNGE acidental.
Erros comuns
Os erros frequentes são não validar TLS, usar números de sequência, selecionar a caixa com escrita sem necessidade, buscar BODY[] e marcar e-mails, interpretar apenas o primeiro item de FETCH, salvar filenames de anexos, chamar EXPUNGE automaticamente, registrar conteúdo e repetir operações de escrita após timeout.
Conclusão
imaplib oferece controle detalhado de caixas IMAP, mas exige disciplina. Use IMAP4_SSL com contexto verificado, selecione readonly, prefira UIDs, use BODY.PEEK, limite mensagens e anexos, trate todas as respostas e mantenha exclusões como fluxo explicitamente autorizado.
Consulte a documentação oficial de imaplib e o RFC 9051 do IMAP4rev2. Para automações críticas, combine testes em conta isolada, idempotência, observabilidade e backups.







