mailsync (6409B) - View raw
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176#!/bin/sh # mailsync - synchronize mail accounts. # # Syncs mail for all accounts, or a single account given as an argument. # Displays a notification showing the number of new mails. # Displays a notification for each new mail with its subject displayed. # Runs notmuch to index new mail. # This script can be set up as a cron job for automated mail syncing. # # Copyright (C) 2018-2025 Luke Smith <luke@lukesmith.xyz> # Copyright (C) 2025 awy <awy@awy.one> # # This file is part of aerc-wizard. # # aerc-wizard is free software: you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation, # either version 3 of the License, or (at your option) any later version. # # aerc-wizard is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public # License along with aerc-wizard. If not, see # <https://www.gnu.org/licenses/>. # There are many arbitrary and ugly features in this script because it is # inherently difficult to pass environmental variables to cronjobs and other # issues. It also should at least be compatible with Linux (and maybe BSD) with # Xorg and MacOS as well. # Run only if not already running in other instance pgrep mbsync >/dev/null && { echo "mbsync is already running." exit } # First, we have to get the right variables for the mbsync file, the gopass # archive, notmuch and the GPG home. This is done by searching common profile # files for variable assignments. This is ugly, but there are few options that # will work on the maximum number of machines. eval "$(grep -h -- \ "^\s*\(export \)\?\(MBSYNCRC\|MPOPRC\|PASSWORD_STORE_DIR\|PASSWORD_STORE_GPG_OPTS\|NOTMUCH_CONFIG\|GNUPGHOME\|MAILSYNC_MUTE\|XDG_CONFIG_HOME\|XDG_DATA_HOME\)=" \ "$HOME/.profile" "$HOME/.bash_profile" "$HOME/.zprofile" "$HOME/.config/zsh/.zprofile" "$HOME/.zshenv" \ "$HOME/.config/zsh/.zshenv" "$HOME/.bashrc" "$HOME/.zshrc" "$HOME/.config/zsh/.zshrc" \ "$HOME/.pam_environment" 2>/dev/null)" # For non-interactive shell (e.g. cron job) run only when the GPG key (in $GNUPGHOME or gopass --homedir) is unlocked tty -s || (echo "dummy" | gpg --sign --batch --yes -o /dev/null >/dev/null 2>&1) || exit export GPG_TTY="$(tty)" [ -n "$MBSYNCRC" ] && alias mbsync="mbsync -c $MBSYNCRC" || MBSYNCRC="$HOME/.mbsyncrc" [ -n "$MPOPRC" ] || MPOPRC="$HOME/.config/mpop/config" lastrun="${XDG_CONFIG_HOME:-$HOME/.config}/aerc/.mailsynclastrun" # Settings are different for MacOS (Darwin) systems. case "$(uname)" in Darwin) notify() { osascript -e "display notification \"$2\" with title \"$1\""; } ;; *) case "$(readlink -f /sbin/init)" in *systemd* | *openrc*) export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$(id -u)/bus ;; # *dinit*) export DBUS_SESSION_BUS_ADDRESS=$(grep -E -z "DBUS_SESSION_BUS_ADDRESS" "/proc/$(pgrep -x swaybar)/environ" | sed 's/DBUS_SESSION_BUS_ADDRESS=//') ;; esac notify() { if [ -n "$3" ]; then ACTION=$(notify-send \ --action="default=Open email" \ --action="reply=Reply to email" \ --action="delete=Delete email" \ --app-name="aerc-wizard" -- "$1" "$2") spawn_aerc() { if ! pgrep -x aerc >/dev/null; then # No aerc running, start it setsid -f "$TERMINAL" -e aerc >/dev/null until pgrep -x aerc >/dev/null; do sleep 0.1 done fi } case "$ACTION" in default) spawn_aerc setsid -wf aerc :change-tab "$4" >/dev/null setsid -wf aerc :eml "$3" >/dev/null ;; reply) spawn_aerc setsid -wf aerc :change-tab "$4" >/dev/null setsid -wf aerc :eml "$3" >/dev/null setsid -f aerc :reply -q >/dev/null ;; delete) spawn_aerc setsid -wf aerc :change-tab "$4" >/dev/null setsid -wf aerc :eml "$3" >/dev/null setsid -f aerc :move Trash >/dev/null ;; *) ;; esac else notify-send --app-name="aerc-wizard" -- "$1" "$2" fi } ;; esac # Check account for new mail. Notify if there is new content. syncandnotify() { case "$1" in imap) mbsync -q "$2" ;; pop) mpop -q "$2" ;; esac new=$(find "$HOME/.local/share/mail/$2/"[Ii][Nn][Bb][Oo][Xx]/new/ \ "$HOME/.local/share/mail/$2/"[Ii][Nn][Bb][Oo][Xx]/cur/ \ -type f -newer "$lastrun" 2>/dev/null) newcount=$(echo "$new" | sed '/^\s*$/d' | wc -l) case 1 in $((newcount > 5))) echo "$newcount new mails for $2." [ -z "$MAILSYNC_MUTE" ] && notify "New Mail!" "📬 $newcount new mails in \`$2\` account." ;; $((newcount > 0))) echo "$newcount new mail(s) for $2." [ -z "$MAILSYNC_MUTE" ] && for file in $new; do # Extract and decode subject and sender from mail. subject=$(awk '/^Subject: / && ++n == 1,/^.*: / && ++i == 2' "$file" | head -n-1 | perl -CS -MEncode -ne 'print decode("MIME-Header", $_)' | sed 's/^Subject: //' | tr -d '\n\t') from="$(sed -n "/^From:/ s|From: *|| p" "$file" | perl -CS -MEncode -ne 'print decode("MIME-Header", $_)')" from="${from% *}" from="${from%\"}" from="${from#\"}" notify "📧$from:" "$subject" "$file" "$2" done ;; *) echo "No new mail for $2." ;; esac } allaccounts="$(grep -hs "^\(Channel\|Group\|account\)" "$MBSYNCRC" "$MPOPRC")" allaccounts=$(echo "$allaccounts" | grep -v 'gmail\.com-[^ ]*') # Get accounts to sync. All if no argument. Prefix with `error` if non-existent. IFS=' ' if [ -z "$1" ]; then tosync="$allaccounts" else tosync="$(for arg in "$@"; do for availacc in $allaccounts; do [ "$arg" = "${availacc##* }" ] && echo "$availacc" && break done || echo "error $arg"; done)" fi for account in $tosync; do case $account in Channel*) syncandnotify imap "${account##* }" & ;; Group*) syncandnotify imap "${account##* }" & ;; account*) syncandnotify pop "${account##* }" & ;; error*) echo "ERROR: Account ${account##* } not found." ;; esac done wait notmuch new --quiet pkill -RTMIN+12 "${STATUSBAR:-i3blocks}" #Create a touch file that indicates the time of the last run of mailsync touch "$lastrun"