Sort Email in 10 lines of Python

Sort your email with a ten line Python program.

It logs into your IMAP mailbox and moves list messages to list/ folder.

Why code?

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.

Simple code in 10 lines

from imap_tools import MailBox, AND, OR, Header

with MailBox("tero.example.com").login("tero@example.com", "hunter2", initial_folder="INBOX") as mailbox:
	uids = mailbox.uids(
		OR (
			AND(header=Header("List-Id", "")),
			AND(header=Header("List-Unsubscribe", "")),
		)
	)
	mailbox.move(uids, "list")

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

import logging
from logging import info, debug, error, warning, INFO, WARNING, DEBUG
import imap_tools  # sudo apt-get install python3-imap-tools , in 13-Trixie
from imap_tools import MailBox, AND, OR, Header

logging.basicConfig(level=INFO, format="%(message)s")

major = int(imap_tools.__version__.split(".")[0])
if major<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...")
with MailBox("teromail.example.com").login("tero.karvinen@example.com", "should-i-use-a-password-manager", initial_folder="INBOX") as mailbox:
	info("Logged in.")
	if not mailbox.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.")

See also

Kaukin "ikvk" et al 2025: imap_tools README.rst, also has the manual. Includes message attributes.

Kaukin "ikvk" et al 2025: imap_tools examples/search.py, details of search criteria for Mailbox.uids(), Mailbox.fetch().

Adminstrivia

"Robots sorting mail", AI assisted image generation by Tero Karvinen.