dotfiles/office/.local/bin/neomutt-syncmail
Marty Oehme 7fd3db3e53
mail: Syncmail checks for existence of dependencies before use
In its default pre- and post-hooks, `neomutt-syncmail` now checks if
`imapfilter` and `notmuch` exist before invoking them.

Similarly, it defaults to `pass open` opening a pass coffin if
`pass-coffin` exists.
2025-09-17 12:08:13 +02:00

175 lines
4.4 KiB
Bash
Executable file

#!/usr/bin/env bash
#
# Runs mbsync, with pre-hooks and post-hooks
# by default, the pre-hook first runs imapfilter
# and afterwards the post-hook indexes with notmuch.
#
# At the very least, you will have to set up a gpg
# encrypted file containing the password for your
# remote mailbox. It can be set directly below or
# through the environment variable
# `MBSYNC_PASSWORD_FILE` and should point to any
# gpg decryptable file.
#
# To run without invoking any hooks or retry attempts,
# run `checkmail raw`.
# this will simply invoke a single isync run on all
# boxes with the correct config file set.
#
# To invoke mbsync for a specific group or channel,
# simply run it with `checkmail <channelname>` and
# it will only sync the correspondingly named.
#
# To run your own commands as hooks overwrite the
# environment variables `MBSYNC_PRE` and
# `MBSYNC_POST`. If you want to not have anything run
# for either of them the easiest way is to set the
# corresponding environment variable to true.
# Be careful which commands you put here since they
# will be evaluated without any special precautions.
#
# for more advanced, per-account/channel hooks, see
# https://sourceforge.net/p/isync/feature-requests/8/
# available env vars:
# MBSYNC_MAX_TRIES=3
# MBSYNC_PRE="/bin/usr/cmd-to-run"
# MBSYNC_POST="/bin/usr/cmd-to-run"
# MBSYNC_NOTIFY=1
# MBSYNC_PASSWORD_FILE="/path/to/gpg/file.gpg"
# What to run before and after decrypting the password file.
if pass coffin -v 1>/dev/null 2>&1; then
PASSWORD_CMD="pass open -t 1min"
fi
# POST_PASSWORD_CMD=""
PING_TARGET="9.9.9.9"
prehook() {
if [ "$MBSYNC_PRE" != "" ]; then
eval "$MBSYNC_PRE"
return 0
fi
checkwarnuser
if command -v imapfilter 1>/dev/null 2>&1; then
imapfilter -c "${XDG_CONFIG_HOME:-$HOME/.config}/imapfilter/config.lua"
fi
}
posthook() {
if [ "$MBSYNC_POST" != "" ]; then
eval "$MBSYNC_POST"
return 0
fi
if command -v notmuch 1>/dev/null 2>&1; then
notmuch new 2>/dev/null
countnew
fi
}
# use notmuch to index incoming mail and set the
# correct number of mails if new ones arrived for notifications
countnew() {
num=$(notmuch count tag:unread and tag:inbox)
HASMAIL="${num:-0}"
}
# fail the routine and optionally send a message why
fail() {
[ "$1" != "" ] && echo "$1"
exit 1
}
checkmail() {
mbsync -c "${XDG_CONFIG_HOME:-$HOME/.config}/isync/mbsyncrc" "${1:--a}"
}
checkonline() {
# Ping 1.1.1.1 to confirm that we are on the internet
ping -c 1 "$PING_TARGET" >/dev/null 2>/dev/null || fail "checkmail cannot access the internet."
}
# warn user that he has to enter his password in a moment
# to stop catching him offguard or entering something by accident
checkwarnuser() {
enablegpgagent
if echo "$agt" | grep -qE 'No secret key'; then
notify "Mail" "Password phrase needed!"
sleep 2.5
fi
}
enablegpgagent() {
[ "$agt" != "" ] && return
if [ "$PASSWORD_CMD" != "" ]; then
IFS=" " read -r -a PASSWORD_CMD <<<"$PASSWORD_CMD"
# shellcheck disable=SC2068
agt=$("${PASSWORD_CMD[@]}")
fi
if [ "$POST_PASSWORD_CMD" != "" ]; then
IFS=" " read -r -a POST_PASSWORD_CMD <<<"$POST_PASSWORD_CMD"
"${POST_PASSWORD_CMD[@]}"
fi
## exit program after first failed attempt
if echo "$agt" | grep -qE 'decryption failed' ||
echo "$agt" | grep -qE 'No such file'; then
notify "Mail" "Process aborted."
exit 1
fi
}
# send out a notification on new mail, to libnotify and stdout
notify_on_new_mail() {
[ "${MBSYNC_NOTIFY:-1}" -eq 0 ] && return
if [ "${HASMAIL:-0}" -gt 0 ]; then
notify "Mail" "New Mail ($HASMAIL)"
fi
}
notify() {
command -v notify-send >/dev/null && notify-send "$@"
echo "$@"
}
# Routine start
# check
# skip any retries and pre/post hooks, just run mbsync
if [ "$1" = "raw" ]; then
checkmail
exit
# any other argument passed through selects mbsync targets
elif [ "$1" != "" ]; then
selected_mailbox="$1"
fi
main() {
enablegpgagent
prehook
tries=0
while true; do
if checkmail "$selected_mailbox"; then
break
fi
tries=$((tries + 1))
if [ "$tries" -gt "${MBSYNC_MAX_TRIES:-3}" ]; then
fail "maximum retries reached without success."
fi
done
unset tries
posthook
notify_on_new_mail
}
main