Apagando e-mails automaticamente no Apple Mail com AppleScript + launchd

Minha caixa de entrada vive cheia de notificações com assunto no formato [Ticket ID: 12345] Atualização do chamado. Elas são úteis por algumas horas e depois viram ruído. Não são e-mails que precisam ser arquivados, respondidos ou revisitados, então acabam só ocupando espaço mental.

Apagar manualmente é aquele tipo de tarefa pequena que nunca vira prioridade, mas que cobra juros em distração. Então resolvi tratar como qualquer outro problema recorrente: automatizar localmente, sem depender de serviço externo, sem webhook e sem integrações. A ideia é rodar periodicamente um script que mova para o lixo as mensagens cujo assunto contenha um padrão específico e que tenham mais de 48 horas.

Por que não usar uma regra do Mail

O primeiro impulso é usar as regras nativas do Mail, em Ajustes > Regras. Elas funcionam bem para agir no momento em que a mensagem chega, mas esse é justamente o problema: elas só rodam no evento de recebimento.

O Mail não oferece um critério do tipo “aplique esta regra apenas se a mensagem tiver mais de 48 horas”, porque não existe reavaliação por idade. Com AppleScript, por outro lado, dá para acessar os objetos internos do Mail.app, incluindo date received. Isso permite comparar datas e tomar decisões baseadas em tempo.

O script

O núcleo da automação é este:

property subjectPattern : "[Ticket ID: "
property maxAgeHours : 48

on run
    set cutoffDate to (current date) - (maxAgeHours * 60 * 60)
    set totalDeleted to 0

    tell application "Mail"
        repeat with acct in accounts
            try
                set inboxMailbox to mailbox "INBOX" of acct

                set matchingMessages to (messages of inboxMailbox whose subject contains subjectPattern and date received < cutoffDate)

                set msgCount to count of matchingMessages
                if msgCount > 0 then
                    repeat with i from msgCount to 1 by -1
                        try
                            delete item i of matchingMessages
                            set totalDeleted to totalDeleted + 1
                        on error errMsg
                            log "Erro ao apagar mensagem: " & errMsg
                        end try
                    end repeat
                end if
            on error errMsg
                log "Erro ao acessar conta: " & errMsg
            end try
        end repeat

        if totalDeleted > 0 then
            try
                check for new mail
            on error errMsg
                log "Aviso: não foi possível sincronizar: " & errMsg
            end try
        end if

        log "Automação concluída: " & totalDeleted & " mensagem(ns) movida(s) para o lixo."
    end tell
end run

Ele percorre todas as contas configuradas no Mail, acessa a INBOX de cada uma e seleciona apenas as mensagens cujo assunto contenha o padrão definido e cuja data de recebimento seja anterior ao limite calculado.

Nada é apagado permanentemente. O comando delete no Apple Mail apenas move para o Lixo da respectiva conta, o que dá margem para recuperar algo se necessário.

O detalhe que evita uma enxurrada de erros

A primeira versão que escrevi iterava mensagem por mensagem, mais ou menos assim:

-- ❌ Abordagem problemática
repeat with msg in inboxMessages
    set msgSubject to subject of msg
    ...
end repeat

Na prática, isso vira uma sequência de erros do tipo:

Mail got an error: Can't get message id 154604 of mailbox "INBOX" of account id "..."

O motivo costuma aparecer em contas IMAP: o AppleScript mantém referências internas por índice ou ID, e essas referências podem ficar inválidas quando há sincronização em andamento, mudanças de índice ou mensagens movidas pelo servidor durante a iteração.

A solução foi delegar a filtragem ao próprio Mail com whose:

-- ✅ Abordagem correta
set matchingMessages to (messages of inboxMailbox whose subject contains subjectPattern and date received < cutoffDate)

Nesse formato, a consulta é resolvida internamente pelo Mail, que retorna apenas referências que ele consegue materializar. Na prática, isso derruba quase todos os erros intermitentes.

Deletando de trás para frente

Ao remover itens de uma coleção, a ordem importa. Se você percorre do primeiro para o último, os índices mudam a cada exclusão e você pode acabar pulando mensagens.

Por isso o loop reverso:

repeat with i from msgCount to 1 by -1
    delete item i of matchingMessages
end repeat

Isso evita inconsistência e mantém o comportamento previsível.

contains em vez de regex

AppleScript não tem suporte nativo a expressões regulares. O operador contains já resolve bem quando o padrão é uma substring fixa como [Ticket ID: , e ainda evita chamar processos externos.

Daria para usar do shell script com grep, mas isso geralmente significa abrir um processo externo por mensagem, o que é mais lento e desnecessário para esse caso.

Atualização visual da interface

Depois que as mensagens vão para o Lixo, a interface do Mail nem sempre atualiza imediatamente. O comando check for new mail força uma sincronização que costuma atualizar a lista na prática.

Outra alternativa seria alternar a mailbox selecionada via AppleScript, mas isso tende a quebrar o contexto de visualizações compostas, que eu uso, como “Todas as Caixas de Entrada”, e nem sempre volta ao estado anterior do jeito certo.

Agendando com launchd

Para rodar periodicamente, o agendamento fica com launchd, não com cron— que o Macos até tem, mas cujo uso é desencorajado. O .plist vai em ~/Library/LaunchAgents/:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.user.delete-ticket-emails</string>

    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/osascript</string>
        <string>/Users/SEU_USUARIO/Scripts/delete_old_ticket_emails.scpt</string>
    </array>

    <key>StartInterval</key>
    <integer>3600</integer>

    <key>RunAtLoad</key>
    <true/>

    <key>StandardOutPath</key>
    <string>/tmp/delete-ticket-emails.log</string>

    <key>StandardErrorPath</key>
    <string>/tmp/delete-ticket-emails-error.log</string>
</dict>
</plist>

StartInterval em 3600 significa execução a cada hora. Se o Mac estiver ligado, o script roda; se não estiver, ele roda na próxima vez que a sessão carregar.

Observe que o caminho do script inclui SEU_USUARIO, que você deve substituir pelo seu próprio nome de usuário no Macos. Se precisar descobrir o seu, rode o comando whoami no Terminal.

Para ativar:

cp com.user.delete-ticket-emails.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/com.user.delete-ticket-emails.plist

Na primeira execução, o macOS deve pedir permissão para que osascript controle o Mail. Essa autorização fica em Ajustes do Sistema > Privacidade e Segurança > Automação. Sem isso, o script falha e o erro nem sempre é muito explicativo.

Personalizando

Para adaptar a outros cenários, basta alterar duas linhas no início do script:

property subjectPattern : "[Ticket ID: "
property maxAgeHours : 48

Você pode usar qualquer substring no assunto e qualquer janela de tempo em horas. O resto do fluxo continua o mesmo.

No fim, não se trata de uma automação para apagar e-mails — não só. Estamos falando em reduzir fricção cognitiva com uma solução simples, local e controlada. O Mail continua sendo o Mail, mas você define que algumas mensagens têm prazo de validade e que, depois disso, elas saem de cena sozinhas.

Newsletter

Gostou deste conteúdo? Informe seu email e receba gratuitamente todos os novos posts na sua caixa de entrada (será necessário confirmar a inscrição em seguida, verifique sua caixa postal).

Deixe seu comentário

Este site utiliza o Akismet para reduzir spam. Saiba como seus dados em comentários são processados.