💾 Archived View for idiomdrottning.org › nmsync captured on 2022-01-08 at 13:46:22. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2021-12-03)

➡️ Next capture (2023-01-29)

-=-=-=-=-=-=-

nmsync

nmsync works with mbsync and notmuch on Unix systems and is programmable in scheme. It’s sort of an alternative to afew except that it also calls mbsync for you and you don’t have to Python.

So this depends on having a working mbsync setup, and Chicken Scheme. I’m not gonna try to make an egg for it because it kinda makes no sense if you don’t compile your own version—the idea is to be able to write more complex tagging and untagging scripts.

I used to have an offlineimap setup that called a tagging shellscript as a hook; as far as I know mbsync doesn’t have hooks in the same way. And nmsync is the solution to that: calling the fetcher from the tagger instead of the other way around.

It checks to see if there’s already an instance of mbsync or nmsync running and if there is, it just quits immediately. Not the most sofisticated mutex in the world but it’s nice to be able to have nmsync being called from cron while still being able to call it manually when you want to specificially get an email someone just told you they sent you without having to worry about them colliding.

(Maybe in a future version there could be inotify on the server instead of polling every X minutes.)

Most of the tagging is done by notmuch’s built in tagfile handling, so for example you might have an ~/.nmsync.tags file that looks like this:

# immediately archive all messages from "me"
-new -- tag:new and from:myownaddress@example.xyz

#paper trail
-new +paper from:billing@example.xyz and subject:"/^Example XYZ - Invoice/" and tag:new
-new +paper from:billing@example.xyz and subject:"/^Example.xyz - Payment Receipt/" and tag:new

#feed
-new +feed -- from:CozyNewsletter@example.xyz and tag:new

#spam
-new +spam -- Xspam:yes and tag:new

# inbox
+inbox +unread +personal -new -- tag:new

That’s just an example, mine is like 40 lines by now.

Notmuch’s internal tagging system can read the tags and combine the multiple operations to run them efficiently, and it can already handle regexes (as seen in the “paper trail” examples above).

So If I can solve an issue by this kind of “vanilla tagging”, I do. Most of my .nmsync.tags is putting things in the feed or in the paper trail (terminology inspired by the proprietary Rails email app “Hey!”, except here I can also sort by subject, body etc.)

I’m not one to overly sort thing by sender or date, since notmuch already is so good at searching senders, date ranges and such. I have a lot of saved searches in emacs, like “search for $terms among email from last seven days” or “show me all threads I’m involved in since midnight” or “show me all email from the last 48 hours“ etc.

By the way, in order to search custom headers like Xspam in my example, run

notmuch config set index.header.Xspam X-Spam

from a shell. That’s just an example, you might have some other cockamamie headers.

In addition to the “vanilla tagging”, nmsync can also do more conditional tagging and untagging via the Scheme code.

An example of complex tagging and untagging

Let’s say I’m using the tagfile to remove +personal and +inbox from invoices and receipts from billing@example.xyz but I still want to get notified if something there isn’t a normal receipt from them.

(let ((latest-invoice (timestamp
               (nm search --limit=1 from:billing@example.xyz
               and "subject:/^Example XYZ - Invoice/"))))
  (when ; When the invoice is newer than the receipt...
      (and (> latest-invoice (timestamp
                  (nm search --limit=1 from:billing@example.xyz
                  and "subject:/^Example.xyz - Payment Receipt/")))
           ; and older than 259200 seconds (four days)
       (> (- (current-seconds) latest-invoice) 259200))
    ; then show all mail from them from the last ten days
    (run (notmuch tag +personal +inbox -new -- from:billing@example.xyz and date:-10_days..))))

The “nm” macro gives you sexps that you can parse; “timestamp” is one example of doing that:

(define (timestamp e)
  (second (find-tail (cut equal? ':timestamp <>) (car e))))

Play around with the sexp tree in the REPL with your typical pretty-printing and SRFI-1 stuff to see its structure.

Obviously, do not mess this up. Be careful. As with all free software, there’s no warranty if you miss invoices etc.

For a jallon, louk git clone https://idiomdrottning.org/nmsync

afew