imapfilter makes it almost easy

Filed under: lua imapfilter 

Despite my issues with Lua, I managed to hack together a little Lua script for automatically filtering the multitude of mailing lists I have.

I was inspired by David Reid's script but needed a bit more since his script only deals with the List-Id header, which I found inadequate in dealing with the tons of mailing lists I subscribe to.

http://blog.twisty-industries.com/images/blog/imapfilter-preview.png

By automatic filtering, I mean I don't create a rule for each list, rather the script inspects the email headers and uses bits of information there to create folders and move the mail there without any intervention.

This was more painful than it needed to be since not all mailing lists carry the same headers, and even headers that might be useful (List-Id) often aren't, due to the vagaries in various mailing list software and how people configure that software.

Anyway, the script is below. Enjoy or don't. If you improve it or find bugs, please let me know here.

config.lua:

imap_acct = {
    server = 'mail.yourserver.com',
    username = 'username',
    password = 'password',
}

function parseListId ( header )
    header = header:lower ( )
    header, n = header:gsub ( '[<>]', ' ' )
    baseheader, n = header:gsub('.*x[-]beenthere:%s*([^%s\r\n]*).*', '%1')
    if n == 0 then
        baseheader, n = header:gsub('.*list[-]post:%s*([^%s\r\n;]*).*', '%1')
    end
    if n == 0 then
        baseheader, n = header:gsub('.*list[-]id:%s*([^%s\r\n]*).*', '%1')
    end
    baseheader, _ = baseheader:gsub ( 'mailto:(.*)', '%1' )

    if n > 0 then
        parts = baseheader:find ( '@' )
        if not parts then
            parts = baseheader:find ( '[.]', 1 )
        end
        parent = baseheader:sub ( parts + 1, nil )
        parent, n = parent:gsub ( '(.*[.])(.*)([.].*)', '%2' )
        if n == 0 then
            parent = parent:gsub ( '(.*)([.].*)', '%1' )
        end
        child = baseheader:sub ( 1, parts -1 )

        -- now, if the parent's name exists in the child, delete that from the child
        child, n = child:gsub ( parent .. '[-]', '' )
    end
    return parent, child
end

mailinglist = {
   invert = true,
   'header "X-BeenThere" ""',
   'header "List-Post" ""',
   'header "List-Id" ""',
}

results = match ( imap_acct, 'INBOX', mailinglist )
listids = fetchfields ( imap_acct, 'INBOX',
                        { 'X-BeenThere', 'List-Post', 'List-Id' }, results ) or { }
mailboxes = { }
for message, header in pairs ( listids ) do
    parent, child = parseListId ( header )
    if parent and child then
        mailbox = parent .. '.' .. child
        if not mailboxes [ mailbox ] then
            mailboxes [ mailbox ] = { }
        end
        table.insert ( mailboxes [ mailbox ], message )
    end
end

for mailbox, messages in pairs ( mailboxes ) do
    -- print ( mailbox )
    move ( imap_acct, 'INBOX', imap_acct, 'Lists.' .. mailbox, messages )
end


0 comments Leave a comment