Вступ

Сьогодні я витратив кілька годин на те, щоб листи надходили до моєї офлайн-скриньки щойно вони з’являються на сервері, причому для кожного з моїх поштових акаунтів.

Інструменти

Припускаю, що ви вже налаштували свій улюблений інструмент для роботи з офлайн-поштою (mu, notmuch тощо), а ваші листи синхронізуються за допомогою чогось на кшталт mbsync (isync). Тобто основи у вас уже є і ви готові до складніших речей.

Якщо ні, ось кілька чудових статей, які допоможуть почати різними способами:

Поштові скриньки

Для цього посібника припустімо, що у вас є файл .mbsyncrc з двома налаштованими скриньками: робочою та особистою. Це означає, що ви можете отримати всю пошту із сервера командою mbsync -a або окремо синхронізувати робочу чи особисту скриньку командами mbsync work і mbsync private.

Зараз ви або запускаєте синхронізацію вручну, або, що ймовірніше, маєте щось на кшталт служби homebrew для isync, яка перевіряє пошту кожні кілька хвилин.

Ми зробимо цей процес таким же безшовним, як на смартфонах: нові листи з’являтимуться у скриньці, щойно надійдуть на сервер.

Встановлення

Спочатку встановімо goimapnotify. Його немає в brew, і для нього потрібно встановити golang, тож:

  1. brew install golang
  2. go install gitlab.com/shackra/goimapnotify@latest
  3. Додайте цільову папку для встановлених через go програм до PATH. Зазвичай це ~/go/bin, тож додайте це до .zshrc:
export PATH=$HOME/go/bin:$PATH

Гаразд, легка частина позаду. Тепер створімо файли конфігурації.

Конфігурація

З якоїсь невідомої причини goimapnotify вважає, що його конфігураційні файли повинні мати розширення .conf, хоча їхній вміст — звичайний json. Ми не будемо дотримуватися цієї дивної схеми й створимо два файли конфігурації json: work.json і private.json.

Припустімо, що ваша робоча пошта на Gmail, а особиста — на Protonmail (як і має бути, бажано з власним доменом, щоб за бажання можна було перейти до іншого провайдера).

work.json

Найпростіша версія work.json для Gmail виглядала б так:

{
    "host": "imap.gmail.com",
    "port": 993,
    "tls": true,
    "username": "your.work.email@gmail.com`,
    "password": "YOUR_PASSWORD",
    "onNewMail": "mbsync work",
    "onNewMailPost": "mu index --lazy-check",
    "boxes": ["INBOX"],
    "wait": 1
}

У цьому файлі ми вказуємо goimapnotify під’єднатися до робочої скриньки Gmail і чекати нових повідомлень. Щойно надходить новий лист, ми чекаємо wait 1 секунду, а потім запускаємо команду onNewMail — mbsync work. Вона звичайним чином завантажує нові повідомлення.

Після цього ми запускаємо команду onNewMailPost, щоб проіндексувати нові листи.

Якщо хочете зробити це безпечнішим, замість прямого зберігання пароля можна отримувати його за допомогою команди на кшталт pass або op (1Password CLI):

{
    "host": "imap.gmail.com",
    "port": 993,
    "tls": true,
    "username": "your.work.email@gmail.com`,
    "passwordCmd": "pass email/work", // [!code focus]
    "onNewMail": "mbsync work",
    "onNewMailPost": "mu index --lazy-check",
    "boxes": ["INBOX"],
    "wait": 1
}

Замість пароля ми задаємо passwordCmd, щоб отримати пароль із pass. Те саме можна зробити з іменем користувача, замінивши username на usernameCmd, і навіть із сервером, замінивши host на hostCmd. Для найбільш параноїдальних.

private.json

Для Protonmail потрібно налаштувати Protonmail Bridge, тож конфігурація виглядатиме так:

{
    "host": "127.0.0.1",
    "port": 1143,
    "tls": false,
    "username": "your.private.email@proton.me",
    "passwordCmd": "pass email/private",
    "onNewMail": "mbsync private",
    "onNewMailPost": "mu index --lazy-check",
    "boxes": ["INBOX"],
    "wait": 10
}

Тепер усе готово до перевірки. Покладіть ці два файли конфігурації будь-де, наприклад у ~/.config/goimapnotify/, і перевірте інтеграцію робочої пошти командою:

goimapnotify -conf ~/.config/goimapnotify/work.json -debug

Параметр -debug забезпечить достатньо повідомлень журналу, щоб зрозуміти, чи все працює.

Тепер достатньо надіслати листа на робочу адресу й стежити за журналом. Якщо все гаразд, після появи листа у скриньці Gmail ви отримаєте повідомлення в журналі, потім спрацюють mbsync і mu, а лист буде доступний у вашому улюбленому офлайн-поштовому клієнті.

Запуск під час входу

Якщо все працює, ви готові до останнього кроку — налаштувати запуск усього цього під час входу. У MacOS для цього потрібно використовувати launchd, а возитися з файлами plist — завжди морока. Якщо знадобиться налагодження, скористайтеся чимось зручним, наприклад LaunchControl: я використовував безкоштовну версію. Є також дуже зручний онлайн-генератор plist launched.. Я його не використовував, але він точно може стати у пригоді.

Для роботи створіть файл com.example.workemail.plist і покладіть його в ~/Library/LaunchAgents:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.example.workemail.plist</string>
    <key>ProgramArguments</key>
    <array>
         <string>/Users/USERNAME/go/bin/goimapnotify</string>
         <string>-conf</string>
         <string>/Users/USERNAME/.config/goimapnotify/work.json</string>
    </array>
    <key>KeepAlive</key>
    <true/>
    <key>RunAtLoad</key>
    <true />
    <key>StandardErrorPath</key>
    <string>/Users/USERNAME/Library/Logs/CheckMailBlaster.err</string>
    <key>StandardOutPath</key>
    <string>/Users/USERNAME/Library/Logs/CheckMailBlaster.log</string>
    <key>EnvironmentVariables</key>
        <dict>
           <key>PATH</key>
           <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/homebrew/bin</string>
        </dict>
</dict>
</plist>

Замініть USERNAME на своє ім’я користувача.

Найскладніше, на що пішла добра година налагодження, — зрозуміти, що запущеному процесу потрібно передати змінну PATH, оскільки він не має доступу до загальносистемної. Поки я цього не зробив, goimapnotify запускався і нормально під’єднувався, але щойно надходив новий лист, я отримував помилку на етапі mbsync.

Отже, як я вже сказав, на налагодження цього простого файлу пішло дві години, тож скажіть дякую і створіть подібний файл для особистої пошти, наприклад com.example.privateemail.plist, у тому самому каталозі.

Тепер залишилося лише запустити:

launchctl load ~/Library/LaunchAgents/com.example.workemail.plist
launchctl load ~/Library/LaunchAgents/com.example.privateemail.plist

Переконайтеся, що вони працюють, за допомогою

launchctl list | grep com.example

Або, ще краще, скористайтеся LaunchControl для спостереження за їхнім станом. Якщо все вдалося, служби запускатимуться щойно ви ввійдете в систему, а пошта миттєво з’являтиметься у вашій скриньці.

Зауважте, що синхронізація почнеться лише з появою нового листа: якщо комп’ютер був вимкнений усю ніч і ви його вмикаєте, синхронізація не почнеться до першого нового листа того дня. Щоб цього уникнути, можна створити подібний plist, який запускається один раз і виконує

mbsync -a

Залишаю це як вправу для читача.