Sometimes a short program is more straightforward than a GUI. (Graphical User Interface. Just slowly drag the octopus over the oval square until it highlights...)
And once the code is working, it works with all the other code we can write. Also, with code you can solve the one corner case that the dumbed down GUI did not let you.
Using Python and imap_tools. Running the script every five minutes using cron is left as an exercise for the reader.
I tested this short version and it actually works.
Sortemail, with logging and some error handling #↑
This longer version
prints log messages as it's proceeding
creates lists/ folder on server if it does not exist
shows how to add some more rules
checks that imported library is the correct version
#!/usr/bin/python3
"sortemail - sort email to folders over IMAP, config in code"# Copyright 2025 Tero Karvinen https://TeroKarvinen.com
# GNU General Public License version 3
importloggingfromloggingimportinfo,debug,error,warning,INFO,WARNING,DEBUGimportimap_tools# sudo apt-get install python3-imap-tools , in 13-Trixie
fromimap_toolsimportMailBox,AND,OR,Headerlogging.basicConfig(level=INFO,format="%(message)s")major=int(imap_tools.__version__.split(".")[0])ifmajor<1:logging.error("Imap-tools {imap_tools.__version__} is too old. We need at least 1.x.x. It's packaged in Debian 13-Trixie, but not in 12-Bookworm. Exiting...")exit()info("Logging in...")withMailBox("teromail.example.com").login("tero.karvinen@example.com","should-i-use-a-password-manager",initial_folder="INBOX")asmailbox:info("Logged in.")ifnotmailbox.folder.exists("list"):logging.info('Creating folder "list"...')mailbox.folder.create("list")info("Subscribing...")mailbox.folder.subscribe("list",True)info("Quick list hits...")info(". List headers, rfc2369: List-Id, List-Unsubscribe ...")uids=mailbox.uids(OR(AND(header=Header("List-Id","")),AND(header=Header("List-Unsubscribe","")),))info(f".. Mass moving {len(uids)} messages...")mailbox.move(uids,"list")info(f".. Mass move of {len(uids)} messages: Done.")info("Specific To or From email addresses...")listAddresses="lists@terokarvinen.example.com cantuselistheaders@company.example.com".split("")uids=mailbox.uids(OR(OR(to=listAddresses),OR(from_=listAddresses)))info(f".. Mass moving {len(uids)} messages...")mailbox.move(uids,"list")info(f".. Mass move of {len(uids)} messages: Done.")info("Done.")
Your own Python web application. From idea to production, in 8 days.
Instagram, Pintrest and Disqus use Django - the exact same framework as the course. Youtube and Facebook are built with Python.
Update: 5.0 /5 feedback. Every participant gave feedback, every response was the best 5. Great students, great time! My comments on feedback.
Previous course feedback was 5.0 /5. Everyone gave feedback, each feedback was the best 5/5). Great mini-projects - I'm baffled by how much you could apply what you learned in just 7 days.