Commit 485e526d8a9b

Vincent Demeester <vincent@sbr.pm>
2025-12-10 15:45:20
feat(imapfilter): Archive emails by year based on date
- Organize archived emails into year-based folders (Archive/2025, etc.) - Use email date header instead of current date for accurate archiving - Improve long-term email organization and historical retrieval Signed-off-by: Vincent Demeester <vincent@sbr.pm>
1 parent 72197dc
Changed files (2)
home/common/services/imapfilter-config.lua
@@ -8,11 +8,11 @@ options.subscribe = true
 -- Accounts
 ----------
 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
-  ssl = 'tls1.2',
+	server = 'imap.mail.me.com',
+	username = 'vdemeester@icloud.com',
+	-- Password will be provided via command line or config file
+	-- Using ssl by default
+	ssl = 'tls1.2',
 }
 
 ----------
@@ -42,47 +42,120 @@ github:move_messages(account['GitHub'])
 -- 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")
+	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 {}
+		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
+end
+
 -- Filter messages from a list of senders
 -- @param messages: message set to filter
 -- @param senders: table/list of email addresses
--- @param action: 'archive' or 'delete'
--- @param archive_folder: folder name for archiving (optional, defaults to 'Archives')
-function filter_by_senders(messages, senders, action, archive_folder)
-  archive_folder = archive_folder or 'Archives'
-  local results = Set {}
+-- @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 {}
 
-  for _, sender in ipairs(senders) do
-    results = results + messages:contain_from(sender)
-  end
+	for _, sender in ipairs(senders) do
+		results = results + messages:contain_from(sender)
+	end
 
-  if action == 'delete' then
-    results:delete_messages()
-  elseif action == 'archive' then
-    results:move_messages(account[archive_folder])
-  else
-    print("Unknown action: " .. action .. ". Use 'archive' or 'delete'")
-  end
+	if action == 'delete' then
+		results:delete_messages()
+	elseif action == 'archive' then
+		archive_by_year(results)
+	elseif action == 'move' then
+		if not folder_name then
+			print("Error: folder_name required for 'move' action")
+			return results
+		end
+		results:move_messages(account[folder_name])
+	else
+		print("Unknown action: " .. action .. ". Use 'archive', 'move', or 'delete'")
+	end
 
-  return results
+	return results
 end
 
 ----------
--- Marketing Email Filters
+-- Email Category Filters
 ----------
 
--- List of marketing senders to archive
-local to_archive = {
-  -- Add your marketing email addresses here
-  -- 'newsletter@example.com',
-  -- 'marketing@company.com',
+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',
 }
 
--- List of marketing senders to delete
-local to_delete = {
-  -- Add email addresses to delete here
-  -- 'spam@example.com',
+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',
 }
-
--- Apply filters (uncomment to enable)
--- filter_by_senders(messages, to_archive, 'archive')
--- filter_by_senders(messages, to_delete, 'delete')
+filter_by_senders(messages, todelete, 'delete')
+filter_by_senders(messages, toarchive, 'archive')
home/common/services/imapfilter.nix
@@ -14,9 +14,10 @@
     Service = {
       Type = "oneshot";
       # Use passage to get the password
-      ExecStart = "${pkgs.bash}/bin/bash -c '${pkgs.imapfilter}/bin/imapfilter -c ${./imapfilter-config.lua} -p <(${pkgs.passage}/bin/passage show mails/icloud/vdemeester)'";
-      # Verbose mode for debugging - uncomment to enable
-      # ExecStart = "${pkgs.bash}/bin/bash -c '${pkgs.imapfilter}/bin/imapfilter -v -c ${./imapfilter-config.lua} -p <(${pkgs.passage}/bin/passage show mails/icloud/vdemeester)'";
+      # Verbose mode enabled for testing new filters
+      ExecStart = "${pkgs.bash}/bin/bash -c '${pkgs.imapfilter}/bin/imapfilter -v -c ${./imapfilter-config.lua} -p <(${pkgs.passage}/bin/passage show mails/icloud/vdemeester)'";
+      # Standard mode (use after testing is complete)
+      # ExecStart = "${pkgs.bash}/bin/bash -c '${pkgs.imapfilter}/bin/imapfilter -c ${./imapfilter-config.lua} -p <(${pkgs.passage}/bin/passage show mails/icloud/vdemeester)'";
     };
   };