noxz-sites

A collection of a builder and various scripts creating the noxz.tech sites
git clone https://noxz.tech/git/noxz-sites.git
Log | Files | README | LICENSE

noxz.tech/articles/simple_way_to_filter_email/index.www
1Having a lot of different types of email had bugged me for some time, so I 
2sought to find a solution to this problem. The logical way of solving this would
3be to somehow filter email automatically into directories based on the type of 
4email, i.e., sender, list id, subject, etc.
5
6I looked into various already available solutions like procmail, notmuch, and 
7alike. The problem with these ways of solving the issue was that they were 
8overly complicated for the problem I needed to solve.
9
10So, I did what I usually do and implemented my own solution instead. As I only 
11wanted to filter email, both new and old ones, by various header data and their 
12age, I only needed to use
13.ICD awk ,
14.ICD grep ,
15.ICD find ,
16and
17.ICD mv .
18To keep it somewhat structured, I wrote everything as a POSIX compliant script, 
19which I programmed to accept a configuration file. As I’m using maildir to store
20my email I made sure the script moved each email based on the directory it 
21resides in \(en
22.I new ,
23.I cur ,
24or
25.I tmp .
26
27This is the script I came up with (feel free to use it as you like):
28
29.CDS
30.COS
31#!/bin/sh
32
33# Copyright © 2022 Chris Noxz <chris@noxz.tech>
34# This work is free. You can redistribute it and/or modify it under the
35# terms of the Do What The Fuck You Want To Public License, Version 2,
36# as published by Sam Hocevar. See http://www.wtfpl.net/ for more details.
37
38# declare default configuration variables
39MAILDIR="${MAILDIR:-"${HOME}/mail"}"
40MAILFILTERRC="${MAILFILTERRC:-"${HOME}/.config/mfrc"}"
41
42# This script is used for applying sorting/filtering rules to maildirs
43# Use the following format for rules:
44# src|pat|dst
45# src: source directory relative to MAILDIR eg. INBOX or me@domain.com/INBOX
46# pat: regex pattern applied to mail header eg. ^From:.*me@domain.com
47# dst: destination directory relative to MAILDIR eg. Archive or My/Mail
48# example rule: INBOX|^From:.*github.com|github
49# this moves mail from INBOX to github retrieved from the domain github.com
50#
51# age based patterns can be used for archiving old emails ($AGE+<days>).
52# example rule: INBOX|$AGE+365|Archive
53# this archives mail from INBOX to Archive that are 365 days or older
54#
55# rules are read from ~/.config/mfrc by default
56
57# extract rules from rule file based on pattern "src|pat|dst"
58grep -o "^[^#][^|]\\+|[^|]\\+|[^|]\\+$" "${MAILFILTERRC}" | while read -r rule; do
59	# extract source directory
60	src="${MAILDIR}/${rule%%|*}"
61
62	# extract destination directory
63	dst="${MAILDIR}/${rule##*|}"
64
65	# extract pattern
66	ptn="${rule#*|}"
67	ptn="${ptn%%|*}"
68
69	# validate input (at least somewhat)
70	[ ! -d "${src}" ] && continue   # skip if source doesn't exist
71	[ ! -d "${dst}" ] && continue   # skip if destination doesn't exist
72	[ -z "${ptn}" ] && continue     # skip if rule is empty
73
74	# check if age based rule: ^$AGE+...
75	if echo "${ptn}" | grep "^\\$AGE+" >/dev/null; then
76		age="${ptn##*+}"
77		if [ -n "$age" ] && [ "$age" -eq "$age" 2>/dev/null ]; then
78			# find file/mail based on age and move file/mail into correct
79			# subdirectory at destination
80			find "${src}"/* -maxdepth 1 -mtime +"${age}" -type f -exec \\
81			sh -c "f=\\"{}\\"; mv \\"\\${f}\\" \\"${dst}/\\$(dirname \\"\\${f}\\" | xargs basename)/\\"" \\;
82		fi
83		continue # done with this rule, continue with the next one
84	fi
85
86	# find pattern in file/mail until first empty line (only check header)...
87	awk "/^$/{nextfile} /${ptn}/{print FILENAME; nextfile}" "${src}"/*/* |\\
88	while read -r f; do
89		# ...and move file/mail into correct subdirectory at destination
90		mv "$f" "${dst}/$(dirname "${f}" | xargs basename)/"
91	done
92done
93.COE
94.CDE
95
96Rules created in the
97.ICD mfrc
98file can look like this:
99
100.CDS
101.COS
102# === chris@noxz.tech ===
103# =======================
104
105# move messages from github.com
106chris@noxz.tech/INBOX|^From:.*github.com|chris@noxz.tech/github
107
108# move messages from list: wiki.suckless.org
109chris@noxz.tech/INBOX|^List-Id:.*wiki.suckless.org|chris@noxz.tech/suckless-mailing-list/wiki
110
111# move 10 day old messages from INBOX to Archive
112chris@noxz.tech/INBOX|$AGE+10|chris@noxz.tech/Archive
113.COE
114.CDE
115
116I can now run the script either on demand or automatically each time I run
117.ICD mbsync
118to retrieve new email. As it turned out, it was easier to create my own script 
119instead of using an existing way of solving my problem. This solution, however,
120is not the most efficient because every email is examined each time the script 
121runs, rather than just the new ones. This could, of course, be fixed, but would
122mean I would have to create a new function for executing the filter on every 
123email as well.