feat(mail): davmail, offlineimap, notmuch extensions

This commit is contained in:
Pavel Korytov 2021-08-04 11:27:02 +03:00
parent 1be22593a4
commit 9f4a0b1e09
10 changed files with 396 additions and 55 deletions

View file

@ -1,5 +1,6 @@
(specifications->manifest
'(
"openjdk"
"node"
"git-filter-repo"
"virt-manager"

View file

@ -3,4 +3,5 @@
"msmtp"
"parallel"
"notmuch"
"offlineimap"
"python-lieer"))

View file

@ -77,6 +77,13 @@
#:start (make-forkexec-constructor '("/home/pavel/bin/scripts/vpn-start"))
#:stop (make-kill-destructor)))
(define davmail
(make <service>
#:provides '(davmail)
#:respawn? #t
#:start (make-forkexec-constructor '("/home/pavel/bin/davmail"))
#:stop (make-kill-destructor)))
(register-services
mpd
mpd-watcher
@ -88,8 +95,9 @@
xsettingsd
discord-rich-presence
polkit-gnome
vpn)
vpn
davmail)
(action 'shepherd 'daemonize)
(for-each start '(mpd mpd-watcher mcron aw-server aw-watcher-afk aw-watcher-window pulseeffects xsettingsd discord-rich-presence polkit-gnome))
(for-each start '(mpd mpd-watcher mcron aw-server aw-watcher-afk aw-watcher-window pulseeffects xsettingsd discord-rich-presence polkit-gnome davmail))

View file

@ -1,11 +1,12 @@
(setq user-mail-address "thexcloud@gmail.com")
(setq user-full-name "Pavel Korytov")
(let ((default-directory "/home/pavel/.guix-extra-profiles/mail/mail/share/emacs/site-lisp"))
(normal-top-level-add-subdirs-to-load-path))
(my-leader-def "am" 'notmuch)
(use-package notmuch
;; :ensure nil
:commands (notmuch)
:commands (notmuch notmuch-search)
:config
(setq mail-specify-envelope-from t)
(setq message-sendmail-envelope-from 'header)
@ -14,20 +15,47 @@
(setq sendmail-program (executable-find "msmtp"))
(setq send-mail-function #'sendmail-send-it)
(setq mml-secure-openpgp-sign-with-sender t)
(setq notmuch-mua-user-agent-function 'notmuch-mua-user-agent-full)
(add-hook 'notmuch-hello-mode-hook
(lambda () (display-line-numbers-mode 0)))
(setq notmuch-saved-searches
'((:name "inbox (main)" :query "tag:inbox AND tag:main")
(:name "unread (main)" :query "tag:unread AND tag:main")
(:name "sent (main)" :query "tag:sent AND tag:main")
(:name "all mail (main)" :query "tag:main")
(:name "inbox (progin)" :query "tag:inbox AND tag:progin")
(:name "unread (progin)" :query "tag:unread AND tag:progin")
(:name "sent (progin)" :query "tag:sent AND tag:progin")
(:name "all main (progin)" :query "tag:progin")
(:name "drafts" :query "tag:draft")))
(custom-set-faces
`(notmuch-wash-cited-text ((t (:foreground ,(doom-color 'yellow)))))))
(lambda () (display-line-numbers-mode 0))))
(my-leader-def
:infix "am"
"" '(:which-key "notmuch")
"m" 'notmuch)
(setq notmuch-saved-searches
'((:name "drafts" :query "tag:draft")
(:name "main (inbox)" :query "tag:main AND tag:inbox")
(:name "main (unread)" :query "tag:main AND tag:unread")
(:name "main (sent)" :query "tag:main AND tag:sent")
(:name "main (all mail)" :query "tag:main")
(:name "progin (inbox)" :query "tag:progin AND tag:inbox")
(:name "progin (unread)" :query "tag:progin AND tag:unread")
(:name "progin (sent)" :query "tag:progin AND tag:sent")
(:name "progin (all mail)" :query "tag:progin")
(:name "pvkorytov (inbox)" :query "tag:pvkorytov AND tag:inbox")
(:name "pvkorytov (unread)" :query "tag:pvkorytov AND tag:unread")
(:name "pvkorytov (sent)" :query "tag:pvkorytov AND tag:sent")
(:name "pvkorytov (all mail)" :query "tag:pvkorytov")))
(my-leader-def
:infix "am"
"t" '(:which-key "thexcloud@gmail.com")
"ti" '((lambda () (interactive) (notmuch-search "tag:main AND tag:inbox")) :which-key "inbox")
"tu" '((lambda () (interactive) (notmuch-search "tag:main AND tag:unread")) :which-key "unread")
"ts" '((lambda () (interactive) (notmuch-search "tag:main AND tag:sent")) :which-key "sent")
"ta" '((lambda () (interactive) (notmuch-search "tag:main")) :which-key "all mail")
"p" '(:which-key "progin6304@gmail.com")
"pi" '((lambda () (interactive) (notmuch-search "tag:progin AND tag:inbox")) :which-key "inbox")
"pu" '((lambda () (interactive) (notmuch-search "tag:progin AND tag:unread")) :which-key "unread")
"ps" '((lambda () (interactive) (notmuch-search "tag:progin AND tag:sent")) :which-key "sent")
"pa" '((lambda () (interactive) (notmuch-search "tag:progin")) :which-key "all mail")
"e" '(:which-key "pvkorytov@etu.ru")
"ei" '((lambda () (interactive) (notmuch-search "tag:pvkorytov AND tag:inbox")) :which-key "inbox")
"eu" '((lambda () (interactive) (notmuch-search "tag:pvkorytov AND tag:unread")) :which-key "unread")
"es" '((lambda () (interactive) (notmuch-search "tag:pvkorytov AND tag:sent")) :which-key "sent")
"ea" '((lambda () (interactive) (notmuch-search "tag:pvkorytov")) :which-key "all mail"))
(with-eval-after-load 'notmuch
(add-hook 'message-setup-hook 'mml-secure-sign-pgpmime))

View file

@ -13,7 +13,7 @@ other_email=progin6304@gmail.com;
# [[file:Mail.org::*Config][Config:3]]
[new]
tags=new;
ignore=.osync_workdir
ignore=.osync_workdir;.mbsyncstate;.uidvalidity;.lock;/.*gmailieer\.json.*/
# Config:3 ends here
# [[file:Mail.org::*Config][Config:4]]

View file

@ -24,6 +24,7 @@ Parts prefixed with (OFF) are not used, but kept for historic purposes. For some
- [[#colors-in-xresources][Colors in Xresources]]
- [[#fonts][Fonts]]
- [[#themes][Themes]]
- [[#device-specific-settings][Device-specific settings]]
- [[#i3wm][i3wm]]
- [[#general-settings][General settings]]
- [[#managing-windows][Managing windows]]
@ -98,6 +99,8 @@ Parts prefixed with (OFF) are not used, but kept for historic purposes. For some
- [[#pulseeffects][PulseEffects]]
- [[#xsettingsd][xsettingsd]]
- [[#discord-rich-presence][Discord rich presence]]
- [[#polkit-authentication-agent][Polkit Authentication agent]]
- [[#vpn][VPN]]
- [[#shepherd-config][Shepherd config]]
- [[#sync][Sync]]
- [[#guix-settings][Guix settings]]
@ -2105,6 +2108,7 @@ This section generates manifests for various desktop software that I'm using.
| dev | virt-manager |
| dev | git-filter-repo |
| dev | node |
| dev | openjdk |
** Manifests
#+NAME: packages
#+begin_src emacs-lisp :tangle no :var category=""
@ -2352,6 +2356,15 @@ Run my [[file:Guix.org::*VPN][OpenVPN setup]]. Not lauching this automatially, a
#:start (make-forkexec-constructor '("/home/pavel/bin/scripts/vpn-start"))
#:stop (make-kill-destructor)))
#+end_src
** Davmail
#+begin_src scheme
(define davmail
(make <service>
#:provides '(davmail)
#:respawn? #t
#:start (make-forkexec-constructor '("/home/pavel/bin/davmail"))
#:stop (make-kill-destructor)))
#+end_src
** Shepherd config
Register services
#+begin_src scheme
@ -2366,7 +2379,8 @@ Register services
xsettingsd
discord-rich-presence
polkit-gnome
vpn)
vpn
davmail)
#+end_src
Daemonize shepherd
@ -2376,7 +2390,7 @@ Daemonize shepherd
Run services
#+begin_src scheme
(for-each start '(mpd mpd-watcher mcron aw-server aw-watcher-afk aw-watcher-window pulseeffects xsettingsd discord-rich-presence polkit-gnome))
(for-each start '(mpd mpd-watcher mcron aw-server aw-watcher-afk aw-watcher-window pulseeffects xsettingsd discord-rich-presence polkit-gnome davmail))
#+end_src
** Sync
| Guix dependency |

312
Mail.org
View file

@ -7,12 +7,15 @@
#+PROPERTY: header-args:conf-space :comments link
#+PROPERTY: header-args:bash :tangle-mode (identity #o755) :comments link :shebang "#!/usr/bin/env bash"
My email configuration with [[https://notmuchmail.org/][notmuch]] + [[https://github.com/gauteh/lieer][lieer]] + [[https://marlam.de/msmtp/][msmtp]]. My problem with any particular mail setup was that I use Gmail labels quite extensively, and handling these over IMAP is rather awkward. Hence this choice of software.
My email configration. Currently uses [[https://github.com/gauteh/lieer][lieer]] to fetch emails from Gmail, [[http://davmail.sourceforge.net/][davmail]] & [[http://www.offlineimap.org/][offlineimap]] to fetch emails from MS Exchange, [[https://notmuchmail.org/][notmuch]] to index, [[https://marlam.de/msmtp/][msmtp]] to send emails. Also using notmuch frontend from Emacs.
My problem with any particular mail setup was that I use Gmail labels quite extensively, and handling these over IMAP is rather awkward. Notmuch seems to be the only software which provides the same first-class support for labels.
But I also have an Exchange account, with which I communicate via IMAP/SMTP adapter, and in this case I syncronize notmuch tags and IMAP folders.
References:
- [[https://sqrtminusone.xyz/posts/2021-02-27-gmail/][My post]] about email configuration. I wrote it some time ago, but the general idea remains.
* Contents
:PROPERTIES:
:TOC: :include all
@ -20,14 +23,18 @@ References:
:CONTENTS:
- [[#contents][Contents]]
- [[#lieer][Lieer]]
- [[#davmail][DavMail]]
- [[#offlineimap][OfflineIMAP]]
- [[#notmuch][Notmuch]]
- [[#config][Config]]
- [[#hooks][Hooks]]
- [[#pre_new][pre_new]]
- [[#post_new][post_new]]
- [[#sync-script][Sync script]]
- [[#mstp][MSTP]]
- [[#msmtp][MSMTP]]
- [[#emacs][Emacs]]
- [[#saved-filters-and-keybindings][Saved filters and keybindings]]
- [[#signing-messages][Signing messages]]
- [[#mailcap][mailcap]]
- [[#guix-settings][Guix settings]]
:END:
@ -53,6 +60,74 @@ gmi set --ignore-tags-local new
#+end_example
Running =gmi sync= in the required directory performs the synchronization. The first sync takes a while, the subsequent syncs are pretty fast.
* DavMail
[[davmail.sourceforge.net][DavMail]] is a gateway bettwen MS Exchange and the rest of the world, which uses IMAP/SMTP/LDAP/etc. As I have one corporate MS Exchange address, this is just the program I need. As of yet, it isn't packaged for Guix, but it's easy enough to download.
It has a GUI mode, but I prefer headless config.
#+begin_src conf-unix :tangle ~/bin/davmail-6.0.0-3375/davmail.properties
davmail.server=true
davmail.mode=Auto
davmail.url=https://mail.etu.ru/owa/
davmail.caldavPort=1080
davmail.imapPort=1143
davmail.ldapPort=1389
davmail.popPort=1110
davmail.smtpPort=1025
davmail.imapAutoExpunge=false
davmail.enableKeepalive=false
#+end_src
Also it's a bit of problem to get it launched as it looks for some jars in pwd, so here is a script.
#+begin_src bash :tangle ~/bin/davmail
cd $HOME/bin/davmail-6.0.0-3375
./davmail davmail.properties
#+end_src
Shepherd service is defined in [[file:Desktop.org::*Davmail][Desktop.org]].
* OfflineIMAP
| Guix dependency |
|-----------------|
| offlineimap |
[[https://github.com/OfflineIMAP/offlineimap][OfflineIMAP]] is a program which can syncronize IMAP mailbox and maildir. Lieer does everything by itself, but my pirate Exchange IMAP needs this program. There is also [[https://isync.sourceforge.io/][isync]], but I had some weird issues with duplicate UIDs, which don't occur for OfflineIMAP.
I have a few options of setting username and password. First, I can run =pass= in =remotepasswordeval=, and this is fine, but it will keep by keyring unlocked, because I want to run =offlineimap= every couple of minutes.
Another option is to use noweb and not push the file below to the version control. Then I have a plaintext password of email on my computer, but I think it's lesser evil than the entire keyring.
#+NAME: mail-username
#+begin_src emacs-lisp
(password-store-get-field "Job/Infrastructure/pvkorytov@etu.ru" "username")
#+end_src
#+NAME: mail-password
#+begin_src emacs-lisp
(password-store-get "Job/Infrastructure/pvkorytov@etu.ru")
#+end_src
#+begin_src conf-unix :tangle ~/.offlineimaprc :noweb yes
[general]
accounts = pvkorytov
[Account pvkorytov]
localrepository = pvkorytov-local
remoterepository = pvkorytov-remote
[Repository pvkorytov-local]
type = Maildir
localfolders = ~/Mail/pvkorytov_etu/
[Repository pvkorytov-remote]
type = IMAP
remotehost = localhost
remoteuser = <<mail-username()>>
remotepass = <<mail-password()>>
remoteport = 1143
starttls = no
ssl = no
#+end_src
* Notmuch
| Guix dependency |
|-----------------|
@ -87,7 +162,7 @@ A list of tags which will be added by =notmuch new= and directory names which wi
#+begin_src conf-unix
[new]
tags=new;
ignore=.osync_workdir
ignore=.osync_workdir;.mbsyncstate;.uidvalidity;.lock;/.*gmailieer\.json.*/
#+end_src
Exclude these tags from search by default.
@ -103,24 +178,123 @@ synchronize_flags=true
#+end_src
** Hooks
Now, we have to link up lieer and notmuch. This is done via the notmuch hook system, which allows to run custom scripts before and after any command.
Now we have to link up lieer & maildir and with notmuch. This is done via the notmuch hook system, which allows to run custom scripts before and after any command.
With lieer and Gmail, it is enough to simply run the program, because Gmail has first-class support for tags. Maildir does not, so I decide to syncronize notmuch tags and IMAP folders. In essence, the idea is to:
- move mails to their folders by tags /before/ the syncronization
- tag mails by their folders /after/ the syncronization
The problem is that with that approach one email can have only one tag, but it's better than nothing.
So, here are the rules which match tags & folders:
#+NAME: pvkorytov_tags
| tag | folder |
|--------------------------+--------------------------|
| inbox | INBOX |
| sent | Sent |
| spam | Junk |
| trash | Trash |
| job.digital | Job_Digital |
| job.digital.docs | Job_Digital.Docs |
| job.digital.support | Job_Digital.Support |
| job.digital.superservice | Job_Digital.Superservice |
And below is a noweb function, which generates the following commands for notmuch to execute:
- /before/ sync:
- =notmuch search --output files "NOT path:[PATH] AND tag:[TAG] AND tag:[ROOT_TAG]" | xargs -I ! mv ! [PATH]=
Move emails with =TAG= but outside the matching =PATH= to the latter
- =notmuch search --output=files "NOT path:[ARCHIVE_PATH] AND tag:[ROOT_TAG] AND NOT tag:[TAG1] ... AND NOT tag:[TAGN]" | xargs -I ! mv ! [ARCHIVE_PATH]=
Move untagged emails to the =ARCHIVE_PATH=
- /after/ sync:
- =notmuch tag +[TAG] "path:[PATH] AND NOT tag:[TAG]"=
Tag emails in =PATH= which do not yet have the matching =TAG=
- =notmuch tag -[TAG] "NOT path:[PATH] AND tag:[TAG] AND tag:[ROOT_TAG]"=
Remove =TAG= from emails which are outside the matching =PATH=
These rules are getting included in the respective hooks.
#+NAME: mail-tags
#+begin_src emacs-lisp :var tags=pvkorytov_tags root="pvkorytov_etu" root_tag="pvkorytov" make_tag="" remove="" move="" archive_root=""
(setq my/maildir-root "~/Mail")
(let ((rules '()))
(dolist (row tags)
(let ((tag (nth 0 row))
(folder (nth 1 row)))
(unless (string-empty-p make_tag)
(add-to-list
'rules
(format "notmuch tag +%s \"path:%s/%s/cur/** AND NOT tag:%s\""
tag root folder tag)
t))
(unless (string-empty-p remove)
(add-to-list
'rules
(format "notmuch tag -%s \"NOT path:%s/%s/cur/** AND tag:%s AND tag:%s\""
tag root folder tag root_tag)
t))
(unless (string-empty-p move)
(add-to-list
'rules
(concat
(format "notmuch search --output=files \"NOT path:%s/%s/cur/** AND tag:%s AND tag:%s\""
root folder tag root_tag)
(format " | xargs -I ! mv ! %s/%s/%s/cur/" my/maildir-root root folder))
t))))
(unless (string-empty-p archive_root)
(add-to-list
'rules
(concat
(format "notmuch search --output=files \"NOT path:%s/%s/cur/** AND %s AND tag:%s\""
root archive_root
(mapconcat
(lambda (row)
(format "NOT tag:%s" (car row)))
tags
" AND ")
root_tag)
(format " | xargs -I ! mv ! %s/%s/%s/cur/" my/maildir-root root archive_root))
t))
(string-join rules "\n"))
#+end_src
*** =pre_new=
This hook runs fetch from Gmail in parallel before the =notmuch new= command.
This hook runs fetch from Gmail & offlineimap in parallel before the =notmuch new= command. The =parallel= command is provided by [[https://www.gnu.org/software/parallel/][GNU Parallel]].
The =parallel= command is provided by [[https://www.gnu.org/software/parallel/][GNU Parallel]].
It isn't necessary to run =cd= for offlineimap, but it's easier to write that way.
#+begin_src bash :tangle ~/Mail/.notmuch/hooks/pre-new
#+NAME: pre-new-pvkorytov-tags
#+begin_src emacs-lisp :var tags=pvkorytov_tags
(my/mail-format-tags-rules tags "pvkorytov_etu" "pvkorytov" nil nil t "Archive")
#+end_src
#+begin_src bash :tangle ~/Mail/.notmuch/hooks/pre-new :noweb yes
# GMI="/home/pavel/Programs/miniconda3/envs/mail/bin/gmi"
GMI="gmi"
parallel -j0 "(cd /home/pavel/Mail/{}/ && $GMI sync)" ::: thexcloud progin6304
echo "Running pre-new filters"
<<mail-tags(move="t",archive_root="Archive")>>
echo "Pre-new filters done"
parallel --link -j0 "(cd /home/pavel/Mail/{1}/ && {2} {3})" ::: thexcloud progin6304 pvkorytov_etu ::: "$GMI" "$GMI" "offlineimap" ::: sync sync ""
#+end_src
*** =post_new=
And this hook tags different mailboxes with different tags.
#+begin_src bash :tangle ~/Mail/.notmuch/hooks/post-new
#+NAME: post-new-pvkorytov-tags
#+begin_src emacs-lisp :var tags=pvkorytov_tags
(my/mail-format-tags-rules tags "pvkorytov_etu" "pvkorytov" t t)
#+end_src
#+begin_src bash :tangle ~/Mail/.notmuch/hooks/post-new :noweb yes
notmuch tag +main "path:thexcloud/** AND tag:new"
notmuch tag +progin "path:progin6304/** AND tag:new"
notmuch tag +pvkorytov "path:pvkorytov_etu/** AND tag:new"
echo "Running post-new filters"
<<mail-tags(make_tag="t",remove="t")>>
echo "Post-new filters done"
notmuch tag -new "tag:new"
#+end_src
* Sync script
@ -143,10 +317,12 @@ ALL_UNREAD=$(notmuch count "$ALL_QUERY")
if [ $NEW_UNREAD -gt 0 ]; then
MAIN_UNREAD=$(notmuch count "tag:unread AND tag:main")
PROGIN_UNREAD=$(notmuch count "tag:unread AND tag:progin")
ETU_UNREAD=$(notmuch count "tag:unread AND tag:pvkorytov")
read -r -d '' NOTIFICATION <<EOM
$NEW_UNREAD new messages
$MAIN_UNREAD thexcloud@gmail.com
$PROGIN_UNREAD progin6304@gmail.com
$ETU_UNREAD pvkorytov@etu.ru
$ALL_UNREAD total
EOM
notify-send "New Mail" "$NOTIFICATION"
@ -159,7 +335,7 @@ The script is ran via GNU Mcron every 5 minutes.
#+begin_src scheme :tangle ~/.config/cron/mail.guile
(job "*/5 * * * * " "~/bin/scripts/check-email")
#+end_src
* MSTP
* MSMTP
| Guix dependency |
|-----------------|
| msmtp |
@ -186,26 +362,38 @@ port 587
from progin6304@gmail.com
user progin6304@gmail.com
passwordeval "pass show My_Online/ETU/progin6304@gmail.com | head -n 1"
account pvkorytov
tls off
auth plain
host localhost
port 1025
from pvkorytov@etu.ru
user pvkorytov
passwordeval "pass show Job/Infrastructure/pvkorytov@etu.ru | head -n 1"
#+end_src
* Emacs
:PROPERTIES:
:header-args+: :tangle ~/.emacs.d/mail.el
:END:
Finally, Emacs configuration.
Finally, Emacs configuration. Let's start with some variables:
#+begin_src emacs-lisp
(setq user-mail-address "thexcloud@gmail.com")
(setq user-full-name "Pavel Korytov")
#+end_src
The problem with my Guix setup is that Emacs by default doesn't see the elisp files of notmuch, so here is a small workaround:
Then, the problem with my Guix setup is that Emacs by default doesn't see the elisp files of notmuch, so here is a small workaround:
#+begin_src emacs-lisp
(let ((default-directory "/home/pavel/.guix-extra-profiles/mail/mail/share/emacs/site-lisp"))
(normal-top-level-add-subdirs-to-load-path))
(my-leader-def "am" 'notmuch)
#+end_src
And the proper notmuch settings:
Finally the proper notmuch settings:
#+begin_src emacs-lisp
(use-package notmuch
;; :ensure nil
:commands (notmuch)
:commands (notmuch notmuch-search)
:config
(setq mail-specify-envelope-from t)
(setq message-sendmail-envelope-from 'header)
@ -214,24 +402,90 @@ And the proper notmuch settings:
(setq sendmail-program (executable-find "msmtp"))
(setq send-mail-function #'sendmail-send-it)
(setq mml-secure-openpgp-sign-with-sender t)
(setq notmuch-mua-user-agent-function 'notmuch-mua-user-agent-full)
(add-hook 'notmuch-hello-mode-hook
(lambda () (display-line-numbers-mode 0)))
(setq notmuch-saved-searches
'((:name "inbox (main)" :query "tag:inbox AND tag:main")
(:name "unread (main)" :query "tag:unread AND tag:main")
(:name "sent (main)" :query "tag:sent AND tag:main")
(:name "all mail (main)" :query "tag:main")
(:name "inbox (progin)" :query "tag:inbox AND tag:progin")
(:name "unread (progin)" :query "tag:unread AND tag:progin")
(:name "sent (progin)" :query "tag:sent AND tag:progin")
(:name "all main (progin)" :query "tag:progin")
(:name "drafts" :query "tag:draft")))
(custom-set-faces
`(notmuch-wash-cited-text ((t (:foreground ,(doom-color 'yellow)))))))
(lambda () (display-line-numbers-mode 0))))
#+end_src
The file to which this is tangled is read in the init.el.
** Saved filters and keybindings
I want to have the saved filters available in both notmuch interface as as keybindings. So a bit more of abusing org tables.
Root keybindings:
#+begin_src emacs-lisp
(my-leader-def
:infix "am"
"" '(:which-key "notmuch")
"m" 'notmuch)
#+end_src
#+NAME: root_tags
| Root tag | Prefix | Keybinding description |
|-----------+--------+------------------------|
| main | t | thexcloud@gmail.com |
| progin | p | progin6304@gmail.com |
| pvkorytov | e | pvkorytov@etu.ru |
#+NAME: filter_tags
| Tag | Prefix | Name |
|--------+--------+----------|
| inbox | i | inbox |
| unread | u | unread |
| sent | s | sent |
| | a | all mail |
The following formats the tables above to a proper syntax for =setq notmuch-saved-searches=:
#+NAME: format-notmuch-saved-searches
#+begin_src emacs-lisp :var root_tags=root_tags filter_tags=filter_tags :tangle no
(let ((searches '()))
(dolist (root_tag root_tags)
(dolist (tag filter_tags)
(add-to-list
'searches
(format "(:name \"%s\" :query \"%s\")"
(format "%s (%s)"
(nth 0 root_tag)
(nth 2 tag))
(concat "tag:" (nth 0 root_tag)
(unless (string-empty-p (nth 0 tag))
(concat " AND tag:" (nth 0 tag)))))
t)))
(string-join searches "\n"))
#+end_src
And the following does the same for my general.el definer:
#+NAME: format-notmuch-keybindings
#+begin_src emacs-lisp :var root_tags=root_tags filter_tags=filter_tags :tangle no
(let ((bindings '()))
(dolist (root_tag root_tags)
(add-to-list
'bindings
(format "\"%s\" '(:which-key \"%s\")"
(nth 1 root_tag)
(nth 2 root_tag))
t)
(dolist (tag filter_tags)
(add-to-list
'bindings
(format "\"%s\" '((lambda () (interactive) (notmuch-search \"%s\")) :which-key \"%s\")"
(concat (nth 1 root_tag) (nth 1 tag))
(concat "tag:" (nth 0 root_tag)
(unless (string-empty-p (nth 0 tag))
(concat " AND tag:" (nth 0 tag))))
(nth 2 tag))
t)))
(string-join bindings "\n"))
#+end_src
#+begin_src emacs-lisp :noweb yes
(setq notmuch-saved-searches
'((:name "drafts" :query "tag:draft")
<<format-notmuch-saved-searches()>>))
(my-leader-def
:infix "am"
<<format-notmuch-keybindings()>>)
#+end_src
** Signing messages
#+begin_src emacs-lisp
(with-eval-after-load 'notmuch

View file

@ -1,6 +1,26 @@
#!/usr/bin/env bash
# [[file:../../../Mail.org::*=post_new=][=post_new=:1]]
# [[file:../../../Mail.org::*=post_new=][=post_new=:2]]
notmuch tag +main "path:thexcloud/** AND tag:new"
notmuch tag +progin "path:progin6304/** AND tag:new"
notmuch tag +pvkorytov "path:pvkorytov_etu/** AND tag:new"
echo "Running post-new filters"
notmuch tag +inbox "path:pvkorytov_etu/INBOX/cur/** AND NOT tag:inbox"
notmuch tag -inbox "NOT path:pvkorytov_etu/INBOX/cur/** AND tag:inbox AND tag:pvkorytov"
notmuch tag +sent "path:pvkorytov_etu/Sent/cur/** AND NOT tag:sent"
notmuch tag -sent "NOT path:pvkorytov_etu/Sent/cur/** AND tag:sent AND tag:pvkorytov"
notmuch tag +spam "path:pvkorytov_etu/Junk/cur/** AND NOT tag:spam"
notmuch tag -spam "NOT path:pvkorytov_etu/Junk/cur/** AND tag:spam AND tag:pvkorytov"
notmuch tag +trash "path:pvkorytov_etu/Trash/cur/** AND NOT tag:trash"
notmuch tag -trash "NOT path:pvkorytov_etu/Trash/cur/** AND tag:trash AND tag:pvkorytov"
notmuch tag +job.digital "path:pvkorytov_etu/Job_Digital/cur/** AND NOT tag:job.digital"
notmuch tag -job.digital "NOT path:pvkorytov_etu/Job_Digital/cur/** AND tag:job.digital AND tag:pvkorytov"
notmuch tag +job.digital.docs "path:pvkorytov_etu/Job_Digital.Docs/cur/** AND NOT tag:job.digital.docs"
notmuch tag -job.digital.docs "NOT path:pvkorytov_etu/Job_Digital.Docs/cur/** AND tag:job.digital.docs AND tag:pvkorytov"
notmuch tag +job.digital.support "path:pvkorytov_etu/Job_Digital.Support/cur/** AND NOT tag:job.digital.support"
notmuch tag -job.digital.support "NOT path:pvkorytov_etu/Job_Digital.Support/cur/** AND tag:job.digital.support AND tag:pvkorytov"
notmuch tag +job.digital.superservice "path:pvkorytov_etu/Job_Digital.Superservice/cur/** AND NOT tag:job.digital.superservice"
notmuch tag -job.digital.superservice "NOT path:pvkorytov_etu/Job_Digital.Superservice/cur/** AND tag:job.digital.superservice AND tag:pvkorytov"
echo "Post-new filters done"
notmuch tag -new "tag:new"
# =post_new=:1 ends here
# =post_new=:2 ends here

View file

@ -1,6 +1,19 @@
#!/usr/bin/env bash
# [[file:../../../Mail.org::*=pre_new=][=pre_new=:1]]
# [[file:../../../Mail.org::*=pre_new=][=pre_new=:2]]
# GMI="/home/pavel/Programs/miniconda3/envs/mail/bin/gmi"
GMI="gmi"
parallel -j0 "(cd /home/pavel/Mail/{}/ && $GMI sync)" ::: thexcloud progin6304
# =pre_new=:1 ends here
echo "Running pre-new filters"
notmuch search --output=files "NOT path:pvkorytov_etu/INBOX/cur/** AND tag:inbox AND tag:pvkorytov" | xargs -I ! mv ! ~/Mail/pvkorytov_etu/INBOX/cur/
notmuch search --output=files "NOT path:pvkorytov_etu/Sent/cur/** AND tag:sent AND tag:pvkorytov" | xargs -I ! mv ! ~/Mail/pvkorytov_etu/Sent/cur/
notmuch search --output=files "NOT path:pvkorytov_etu/Junk/cur/** AND tag:spam AND tag:pvkorytov" | xargs -I ! mv ! ~/Mail/pvkorytov_etu/Junk/cur/
notmuch search --output=files "NOT path:pvkorytov_etu/Trash/cur/** AND tag:trash AND tag:pvkorytov" | xargs -I ! mv ! ~/Mail/pvkorytov_etu/Trash/cur/
notmuch search --output=files "NOT path:pvkorytov_etu/Job_Digital/cur/** AND tag:job.digital AND tag:pvkorytov" | xargs -I ! mv ! ~/Mail/pvkorytov_etu/Job_Digital/cur/
notmuch search --output=files "NOT path:pvkorytov_etu/Job_Digital.Docs/cur/** AND tag:job.digital.docs AND tag:pvkorytov" | xargs -I ! mv ! ~/Mail/pvkorytov_etu/Job_Digital.Docs/cur/
notmuch search --output=files "NOT path:pvkorytov_etu/Job_Digital.Support/cur/** AND tag:job.digital.support AND tag:pvkorytov" | xargs -I ! mv ! ~/Mail/pvkorytov_etu/Job_Digital.Support/cur/
notmuch search --output=files "NOT path:pvkorytov_etu/Job_Digital.Superservice/cur/** AND tag:job.digital.superservice AND tag:pvkorytov" | xargs -I ! mv ! ~/Mail/pvkorytov_etu/Job_Digital.Superservice/cur/
notmuch search --output=files "NOT path:pvkorytov_etu/Archive/cur/** AND NOT tag:inbox AND NOT tag:sent AND NOT tag:spam AND NOT tag:trash AND NOT tag:job.digital AND NOT tag:job.digital.docs AND NOT tag:job.digital.support AND NOT tag:job.digital.superservice AND tag:pvkorytov" | xargs -I ! mv ! ~/Mail/pvkorytov_etu/Archive/cur/
echo "Pre-new filters done"
parallel --link -j0 "(cd /home/pavel/Mail/{1}/ && {2} {3})" ::: thexcloud progin6304 pvkorytov_etu ::: "$GMI" "$GMI" "offlineimap" ::: sync sync ""
# =pre_new=:2 ends here

View file

@ -16,10 +16,12 @@ ALL_UNREAD=$(notmuch count "$ALL_QUERY")
if [ $NEW_UNREAD -gt 0 ]; then
MAIN_UNREAD=$(notmuch count "tag:unread AND tag:main")
PROGIN_UNREAD=$(notmuch count "tag:unread AND tag:progin")
ETU_UNREAD=$(notmuch count "tag:unread AND tag:pvkorytov")
read -r -d '' NOTIFICATION <<EOM
$NEW_UNREAD new messages
$MAIN_UNREAD thexcloud@gmail.com
$PROGIN_UNREAD progin6304@gmail.com
$ETU_UNREAD pvkorytov@etu.ru
$ALL_UNREAD total
EOM
notify-send "New Mail" "$NOTIFICATION"