How mailsort works¶
This page explains what actually happens behind the scenes when mailsort sorts your emails. It is written for
curious users who want to understand the mechanics before trusting a program to move their emails around - no prior
machine learning knowledge required. If you are looking for setup instructions instead, see
Preparation and Configuration. If you are looking for the Python API, see
Developer.
The big picture¶
mailsort is built from three building blocks:
Your email account - the source of truth for your emails and folders, accessed through a plain IMAP connection.
mailsortnever stores your account password, it is only used to log in and is not persisted anywhere. Each IMAP folder plays the role a label plays in a system like Gmail - “moving” an email between folders is the unit of sortingmailsortperforms.A local database - a SQL database (SQLite by default, though any database supported by SQLAlchemy works) that keeps a private copy of your email metadata and your trained models. This database lives entirely on your own machine.
One machine learning model per folder - a small classifier trained purely on your own historic emails, which is used to recommend a folder for each new email that arrives in your sorting inbox folder (for example
MailSortInbox).
Unlike a hosted service, mailsort does not run a background job for you - you trigger the loop below yourself,
either manually from the command line or on a schedule with cron (see Configuration).
The fetch-store-train-predict-move loop¶
1. Fetch¶
mailsort asks the IMAP server for the list of message IDs that currently sit in a given folder (for example every
folder you already sorted your inbox into, or - during regular runs - your sorting inbox folder). Only message IDs
and metadata are requested at this stage, so this step is cheap and fast even for large mailboxes.
2. Store¶
For every message ID that is not yet known locally, mailsort downloads the message and splits it into several
normalized tables in the local database: the message content and subject, its thread, its to/cc/from
addresses and the folder it currently sits in. Messages that disappear from the server (for example because you
deleted them) are marked as deleted rather than removed, so your training history stays intact. This mirrors how a
relational database would model any many-to-many relationship - one email can have many recipients and many
folders it has passed through, so each of those gets its own table linked back to the email by its ID.
3. Train¶
This is the step that is easy to get wrong when described casually, so let’s be precise: mailsort does not read the text of your emails to judge similarity. Instead it looks at the metadata surrounding each email you have already sorted:
who sent it, and the domain of the sender (e.g.
@newsletter.example.com),everyone it was addressed to or copied on,
which email thread it belongs to,
and which folder you filed it in.
Each of these values is turned into a binary “yes/no” column through
one-hot encoding (implemented in
src/mailsort/ml/encoding.py) -
so instead of one column “sender”, you get one column per sender that is either 1 or 0. mailsort then trains
one random forest classifier per folder
(see src/mailsort/ml/model.py) to
answer the question “does this email belong to folder X, based on who sent it, who else received it and what other
folders tend to go together?”. In practice this captures the intuition most people actually sort emails by - the
sender, the mailing list or the group of people involved - rather than trying to summarize free text.
The trained models are serialized and stored back in your local database, together with the exact list of columns they were trained on, so they can be reloaded without retraining every time. Where a folder has enough training examples, its model’s scores are also calibrated (rescaled against held-out data so a score more honestly reflects how often it is actually right) rather than used raw - see Evaluation and confidence for what that means and why it only happens when there is enough data to do it safely.
4. Predict¶
When a new email lands in your sorting inbox folder, mailsort encodes it using the very same columns the models
were trained on and asks every stored model for a score for that email. The folder with the highest score wins, but
only if that score clears the recommendation_ratio threshold (90% by default) - recommendation_ratio is a
cutoff on a model score, not a guaranteed error rate; see Evaluation and confidence for why, and for
how to check what a given threshold actually achieves on your own mailbox before trusting it. If no folder’s score
is high enough, the email is simply left where it is until the next run, once more training data has raised the
models’ scores.
5. Move¶
If a folder was recommended with a score above the threshold, mailsort issues an IMAP command to move the email
out of the sorting inbox folder and into the recommended folder - the same action you would take by hand by
dragging the email into a folder. Nothing is deleted or archived silently; the email simply moves to the folder you
would have put it in yourself.
To avoid ever recommending a folder you would not want emails moved into automatically, mailsort skips folders
marked with \Noselect, and special-use folders such as Trash, Spam/Junk, Sent and Drafts, both when training and
when predicting.
If you want to see steps 1-4 of this loop without ever letting mailsort perform step 5, see the dry run /
recommendation mode described in Configuration - it downloads and scores messages exactly as
described above, but stops before moving anything.
Learning from your corrections¶
mailsort does not try to be clever about disagreements - it relies entirely on your folders. If you move an email
to a different folder than the one mailsort suggested, that correction becomes part of the training data the next
time models are retrained (step 3), because training always reads the folder an email currently sits in, not the
folder mailsort last predicted. There is no separate feedback API to call; simply sorting your email as you
normally would is enough.
What is stored, and where¶
The local database contains:
your email metadata (subject, thread, sender, recipients, folder and dates) - not a shared, cross-user index. Each row is scoped to a
db_user_id, so a single database can serve multiple accounts without mixing their data.your trained models, serialized with pickle.
This database lives exclusively wherever you point the -d/--database connection string - typically a local SQLite
file on your own machine. Nothing is shared with any third party.
Limitations to be aware of¶
The model only learns from folders you already filed emails into by hand, so a brand-new folder with very few emails behind it will rarely reach the score needed to be suggested - this is intentional, to avoid confidently wrong guesses, but it does mean new folders take a little time to “warm up”. It also means that folder’s model is not calibrated yet - see Evaluation and confidence.
Because the model deliberately ignores email body text, two emails with very similar content but no overlapping sender, recipients or thread will not be linked by
mailsorttoday. See Developer - Future directions for the direction this may take next.A model score, calibrated or not, is not a guarantee - see Evaluation and confidence for what it actually means and how to check it against your own data with
mailsort evaluatebefore trusting a threshold.