Commit 307e92322194
Changed files (1)
home
common
services
home/common/services/imapfilter-config.lua
@@ -10,93 +10,87 @@ options.subscribe = true
account = IMAP {
server = 'imap.mail.me.com',
username = 'vdemeester@icloud.com',
- -- Password will be provided via command line or config file
- -- Using ssl by default
+ -- Password will be provided via command line (-p flag)
ssl = 'tls1.2',
}
----------
--- Example filtering rules
--- Customize these based on your needs
+-- Rule File Parser
----------
--- Get all messages in INBOX
-messages = account['INBOX']:select_all()
-
--- Example 1: Move GitHub notifications to a GitHub folder
--- Uncomment and customize as needed
-github = messages:contain_from('notifications@github.com')
-github:move_messages(account['GitHub'])
-
--- Example 2: Move mailing list emails
--- Uncomment and customize as needed
--- lists = messages:contain_to('list@example.com')
--- lists:move_messages(account['Lists'])
-
--- Example 3: Filter by subject
--- Uncomment and customize as needed
--- spam = messages:contain_subject('[SPAM]')
--- spam:move_messages(account['Junk'])
-
-----------
--- Helper Functions
-----------
-
--- Extract year from email date header
--- @param message: single message to extract year from
--- @return year as string (e.g., "2025")
-function get_message_year(message)
- -- Get the message headers including Date
- local mbox, uid = table.unpack(message)
- local date_header = mbox[uid]:fetch_header()
-
- -- Try to extract year from Date header
- -- Date format is usually like: "Thu, 10 Dec 2025 10:30:45 +0100"
- local year = date_header:match("Date:.-(%d%d%d%d)")
-
- -- Fallback to current year if we can't parse the date
- if not year then
- year = os.date("%Y")
+-- Load rules from external file
+-- Returns a table with rules organized by type
+function load_rules_from_file(filepath)
+ local rules = {
+ from = {}, -- Sender email addresses
+ domain = {}, -- Email domains
+ subject = {}, -- Subject patterns
+ header = {} -- Header field patterns
+ }
+
+ local file = io.open(filepath, "r")
+ if not file then
+ print("Warning: Could not open rules file: " .. filepath)
+ return rules
end
-
- return year
-end
-
--- Archive messages by year
--- @param message_set: set of messages to archive
-function archive_by_year(message_set)
- -- Group messages by year
- local messages_by_year = {}
-
- for _, msg in ipairs(message_set) do
- local year = get_message_year(msg)
- if not messages_by_year[year] then
- messages_by_year[year] = Set {}
+
+ for line in file:lines() do
+ -- Skip comments and blank lines
+ line = line:match("^%s*(.-)%s*$") -- Trim whitespace
+ if line ~= "" and not line:match("^#") then
+ -- Parse rule format: TYPE:PATTERN
+ local rule_type, pattern = line:match("^(%w+):(.+)$")
+ if rule_type and pattern then
+ rule_type = rule_type:lower()
+ if rules[rule_type] then
+ table.insert(rules[rule_type], pattern)
+ else
+ print("Warning: Unknown rule type '" .. rule_type .. "' in " .. filepath)
+ end
+ else
+ print("Warning: Invalid rule format (expected TYPE:PATTERN): " .. line)
+ end
end
- messages_by_year[year] = messages_by_year[year] + Set {msg}
- end
-
- -- Move messages to year-based archive folders
- for year, msgs in pairs(messages_by_year) do
- local folder_name = 'Archive/' .. year
- -- Ensure the folder exists
- account:create_mailbox(folder_name)
- msgs:move_messages(account[folder_name])
end
+
+ file:close()
+ return rules
end
--- Filter messages from a list of senders
--- @param messages: message set to filter
--- @param senders: table/list of email addresses
--- @param action: 'archive', 'move', or 'delete'
--- @param folder_name: folder name for moving (only used for 'move' action)
-function filter_by_senders(messages, senders, action, folder_name)
- local results = Set {}
+----------
+-- Rule Application Functions
+----------
- for _, sender in ipairs(senders) do
+-- Apply rules to a message set
+function apply_rules(messages, rules, action, folder_name)
+ local results = Set {}
+
+ -- Apply from: rules (sender email)
+ for _, sender in ipairs(rules.from or {}) do
results = results + messages:contain_from(sender)
end
-
+
+ -- Apply domain: rules (entire domain)
+ for _, domain in ipairs(rules.domain or {}) do
+ -- Match emails ending with the domain
+ results = results + messages:contain_from(domain)
+ end
+
+ -- Apply subject: rules (subject patterns)
+ for _, pattern in ipairs(rules.subject or {}) do
+ results = results + messages:contain_subject(pattern)
+ end
+
+ -- Apply header: rules (custom headers)
+ for _, header_pattern in ipairs(rules.header or {}) do
+ -- Parse HEADER-NAME:PATTERN
+ local header_name, pattern = header_pattern:match("^([^:]+):(.+)$")
+ if header_name and pattern then
+ results = results + messages:contain_header(header_name, pattern)
+ end
+ end
+
+ -- Perform the action
if action == 'delete' then
results:delete_messages()
elseif action == 'archive' then
@@ -106,56 +100,84 @@ function filter_by_senders(messages, senders, action, folder_name)
print("Error: folder_name required for 'move' action")
return results
end
+ -- Ensure folder exists
+ account:create_mailbox(folder_name)
results:move_messages(account[folder_name])
else
- print("Unknown action: " .. action .. ". Use 'archive', 'move', or 'delete'")
+ print("Unknown action: " .. action)
end
-
+
return results
end
----------
--- Email Category Filters
+-- Helper Functions
----------
-local todelete = {
- 'contact@news.probikeshop.com',
- 'adidas@fr-news.adidas.com',
- 'contact@email.westfield.com',
- 'soouest@email.westfield.com',
- 'geox@email-geox.com',
- 'shop@emails.flic.io',
- 'shop@mail.nova.fr',
- 'noreply-marketplace.partner@decathlon.com',
- 'noreply@e-ticket.jacadi.com',
- 'bonjour@ferflex.fr',
- 'news@email.arthur.fr',
- 'mailgun@mg.welmo.fr',
- 'info@kiddiprint.com',
- 'confirmation-commande@amazon.fr',
- 'shipment-tracking@amazon.fr',
- 'order-update@amazon.fr',
- 'noreply@audible.fr',
- 'team@email.remarkable.com',
- 'contact@thepihut.com',
- 'email.campaign@sg.booking.com',
- 'info@e.sixt.fr',
- 'noreply@komoot.de',
-}
+-- Archive messages by year
+function archive_by_year(message_set)
+ local messages_by_year = {}
+
+ for _, msg in ipairs(message_set) do
+ local year = get_message_year(msg)
+ if not messages_by_year[year] then
+ messages_by_year[year] = Set {}
+ end
+ messages_by_year[year] = messages_by_year[year] + Set {msg}
+ end
+
+ for year, msgs in pairs(messages_by_year) do
+ local folder_name = 'Archive/' .. year
+ account:create_mailbox(folder_name)
+ msgs:move_messages(account[folder_name])
+ end
+end
-local toarchive = {
- 'pragmaticengineer@substack.com',
- 'pragmaticengineer+deepdives@substack.com',
- 'newsletter@farnamstreetblog.com',
- 'james@jamesclear.com',
- 'bloodinthemachine@substack.com',
- 'peter@golangweekly.com',
- 'learn@semaphore.io',
- 'todoist@substack.com',
- 'hello@readwise.io',
- 'newsletter@quotidien.fr',
- 'support@pragprog.com',
- 'noreply@7digital.com',
-}
-filter_by_senders(messages, todelete, 'delete')
-filter_by_senders(messages, toarchive, 'archive')
+-- Extract year from email date header
+function get_message_year(message)
+ local mbox, uid = table.unpack(message)
+ local date_header = mbox[uid]:fetch_header()
+ local year = date_header:match("Date:.-(%d%d%d%d)")
+ if not year then
+ year = os.date("%Y")
+ end
+ return year
+end
+
+----------
+-- Main Filtering Logic
+----------
+
+-- Load rules from private repository
+local rules_dir = os.getenv("HOME") .. "/.local/share/imapfilter-rules"
+
+print("Loading rules from: " .. rules_dir)
+
+local delete_rules = load_rules_from_file(rules_dir .. "/delete.txt")
+local receipts_rules = load_rules_from_file(rules_dir .. "/receipts.txt")
+local newsletters_rules = load_rules_from_file(rules_dir .. "/newsletters.txt")
+local archive_rules = load_rules_from_file(rules_dir .. "/archive.txt")
+
+-- Get all messages in INBOX
+messages = account['INBOX']:select_all()
+
+-- Apply filters
+print("Applying delete rules...")
+apply_rules(messages, delete_rules, 'delete')
+
+print("Applying receipts rules...")
+apply_rules(messages, receipts_rules, 'move', 'Receipts')
+
+print("Applying newsletters rules...")
+apply_rules(messages, newsletters_rules, 'move', 'Newsletters')
+
+print("Applying archive rules...")
+apply_rules(messages, archive_rules, 'archive')
+
+-- GitHub notifications (existing rule)
+print("Moving GitHub notifications...")
+github = messages:contain_from('notifications@github.com')
+account:create_mailbox('GitHub')
+github:move_messages(account['GitHub'])
+
+print("Filtering complete!")