Apesar de ter me apaixonado pelo Gmail logo que foi lançado, nunca curti webmails1. Por isso, foi um alívio quando o suporte a POP2 e, posteriormente, a IMAP foram adicionados ao serviço.

Assim que o suporte a IMAP foi adicionado, não pensei duas vezes e o adotei. Só existe um probleminha: o Gmail, com seu incentivo a não apagamento de mensagens e sua ideia de marcadores (e o fato de cada marcador ser realizado como uma pasta) gera, em sua implementação de IMAP, um monte de mensagens duplicadas (uma para cada marcador mais a do “All Mail“). As consequências são mais ou menos desastrosas do ponto de vista de bandwidth e de armazenamento: se você tem 5GB de email armazenados, vai baixar, e armazenar, no mínimo 10GB. :-(

Minha solução sempre foi a de não baixar o “All Mail” via IMAP e, quando precisava buscar alguma mensagem sem marcador, recorria à versão web. Não muito inteligente, mas funcionava.

No entanto, como, há cerca de um mês, decidi me livrar do Gmail, era melhor que eu desfizesse os efeitos de minha gambiarra. Notei que o Thunderbird possuía uma extensão de remoção de emails duplicados. Infelizmente, ela não aguentava tratar meus mais de 40 mil emails duplicados. A solução, é claro, foi escrever meu próprio script para realizar a tarefa3!

O script não precisava ser mega robusto ou configurável, já que eu seria, em princípio, seu único usuário. Sua função, portanto, é apagar minhas mensagens indesejadas lá do All Mail e pronto. Então, sua ideia básica é:

  1. Obter uma lista de todas as pastas IMAP;
  2. Passar por todas elas:
  3. Gravando o campo Message-ID de cada uma das mensagens e salvando num hash indexado por Message-ID. Assim, cada um dos slots que tivesse mais de um elemento o teria devido à presença de mensagens duplicadas.

Depois, numa passada pelo hash, é só examinar os Message-IDs que forem mapeados para mais de uma mensagem. Em Python, eu comecei representando uma mensagem como a pasta que a contém seu UID naquela pasta e seu Message-ID:

class Message(object):
    def __init__(self, path, uid, id):
        self.id = id
        self.uid = uid
        self.path = path

Agora, considerando que uma conexão imap autenticada já existe, obter a lista de pastas é moleza:

mboxes = connection.list()

Então é só iterar por cada uma das pastas e pegar a listagem de mensagens (como no script anterior)):

for mbox in mboxes[1]:
    mbox = mbox.split(' "." ')[1].replace('"', '')
    ret, count = connection.select(mbox)
    ret, data = connection.search(None, 'ALL') # data contém a lista de UIDs
    for mnum in data[0].split():
        ret, tmp = connection.fetch(mnum, 'RFC822.HEADER')
        header = Parser().parsestr(tmp[0][1])
        mid = header['Message-ID']
        if mid in cache:
            cache[mid].append(Message(mbox, mnum, mid))
        else:
            cache[mid] = [Message(mbox, mnum, mid)]

Ali em cima eu usei a maravilhosa classe Parser do módulo email.parser da biblioteca padrão do Python para interpretar o conteúdo do cabeçalho da mensagem (RFC822.HEADER lá em cima) e transformá-lo “em” um dicionário. Chique (e confuso), não? Pronto, agora todas as mensagens já estão em cache. Basta detonar aquelas que não quero:

allmail = 'INBOX.Gmail.All Mail' # Quero detonar esse cara
tbd = [] # to be deleted
for key in cache:
    if len(cache[key]) > 1: # Duplicado!
        for msg in cache[key]:
            if msg.path == allmail:
                tbd.append(msg.uid)
conn.select(allmail)
for uid in tbd:
    # Adicionando o flag "Deleted" a todas as duplicadas
    conn.store(uid, '+FLAGS', '\\Deleted')
# Efetivamente deletando-as
conn.expunge()

E é isso. O script completo, na verdade, é um pouco mais complicado que o apresentado acima, mas a ideia é a mesma. Fica aí, caso seja útil para mais alguém. Para mim, foi. Meu “All Mail” foi reduzido para um terço de seu tamanho original.


  1. A paixão estava mais para o lado de 1GB de armazenamento que para a interface inovadora. 

  2. POP era um mal necessário. Acho que é quase melhor usar webmail nesse caso. 

  3. Considerando que minha única aventura via IMAP olhava as datas de mensagens, esse parecia um exercício divertido. 

Related content