Procmail может легко запускать внешнюю команду в состоянии и реагировать на ее состояние выхода. Как именно ваш клиент SQL установит свой код выхода, будет зависеть от того, какой из них вы используете; может быть, на странице man
появится возможность заставить его завершиться с ошибкой, например, когда запрос выдаст пустой набор результатов? Или же написать оболочку оболочки для поиска пустых выходных данных.
Сложность заключается в том, что Procmail (или, скорее, вспомогательная утилита formail
) может легко извлечь строку, например, из заголовка From:
; но вы хотите сократить это только до конца электронной почты. Это достаточно распространенная задача, поэтому легко найти постоянное решение - сгенерировать ответ и , а затем извлечь из этого адрес To:
(si c!).
FROM=`formail -rtzxTo:`
:0
* FROM ?? ^(one@example\.com|two@site\.example\.net|third@example\.org)$
{
:0
* ? yoursql --no-headers --fail-if-empty-result \
--batch --query databasename \
--eval "select yada yada where address = '$FROM'"
{ }
:0E
/dev/null
}
Первое условие проверяет переменную и успешно выполняется, если она содержит один из адресов (мой первоначальный ответ просто содержал регулярное выражение .
, которое соответствует, если строка содержит хотя бы один символ, любой символ; я не уверен, что это действительно необходимо или полезный; не должно быть способа для From:
быть пустым). Если это правда, Procmail вводит скобки; в противном случае они будут пропущены.
Первый рецепт внутри фигурных скобок запускает внешнюю команду и проверяет ее код выхода. Я представляю, что ваш SQL клиент называется yoursql
и что у него есть опции для отключения удобного для пользователя форматирования (заголовки таблиц и т. Д. c) и для запуска запроса непосредственно из командной строки по указанному c база данных. Мы используем двойные кавычки, чтобы оболочка интерполировала переменную FROM
перед выполнением этой команды (возможно, есть более безопасный способ передачи строковых переменных, которые могут содержать SQL попыток внедрения с чем-то вроде --variable from="$FROM"
, а затем использовать эту переменную в запрос? См. ниже.)
Если нет возможности напрямую установить код выхода, но вы можете убедиться, что стандартный вывод полностью пуст, в случае отсутствия результата, передача команды в grep -q .
будет произвести правильный код выхода. В более сложном случае, возможно, напишите простой сценарий Awk, чтобы определить пустой набор результатов и соответственно установить его состояние выхода.
Сбор информации из https://www.postgresql.org/docs/current/app-psql.html, Как сделать Вы используете переменные скрипта в psql? , Делая пустой вывод из psql, и из вашего вопроса я в итоге пытаюсь реализовать это в psql
; но поскольку у меня нет экземпляра Postgres для тестирования или какой-либо информации о вашей схеме базы данных, в лучшем случае это приблизительное значение.
* ? psql --no-align --tuples-only --quiet \
--dbname=databasename --username=something --no-password \
--variable=from="$FROM" \
--command="select email from users where email = :'from'" \
| grep -q .
(Мы по-прежнему не можем использовать одинарные кавычки запрос SQL, чтобы полностью защитить его от оболочки, потому что Postgres настаивает на одинарных кавычках около :'from'
, а оболочка не предоставляет возможности для встраивания буквальных одинарных кавычек в одинарные кавычки.)
окружающий код Procmail должен быть достаточно понятным, но здесь все равно идет. В первом рецепте внутри фигурных скобок, если условие истинно, пустые фигурные скобки в его строке действия запрещены; флаг E
в следующем рецепте является условием, которое выполняется только в том случае, если какое-либо из условий предыдущего рецепта не выполнено. Это обычная идиома, позволяющая избежать использования множества отрицаний; возможно, посмотрите «закон де Моргана». Результатом net является то, что мы отбрасываем сообщение, доставляя его до /dev/null
, если любое из условий в первом рецепте не выполнено; в противном случае мы просто передадим его, и Procmail в конечном итоге доставит его к месту назначения по умолчанию.
Рецепт был реорганизован в ответ на обновления вашего вопроса; возможно, теперь было бы более разумно просто отменить код выхода из psql
с !
впереди:
FROM=`formail -rtzxTo:`
:0
* FROM ?? ^(one@example\.com|two@site\.example\.net|third@example\.org)$
* ! ? psql --no-align --tuples-only --quiet \
--dbname=databasename --username=something --no-password \
--variable=from="$FROM" \
--command="select email from users where email = :'from'" \
| grep -q .
/dev/null
Тангенциально, возможно, обратите внимание, как синтаксис Procmail использует тот факт, что ведущий ?
или удвоенное значение ??
недопустимо в регулярных выражениях. Таким образом, синтаксический анализатор может однозначно сказать, что эти условия не являются регулярными выражениями; они сравнивают переменную с регулярным выражением после ??
или проверяют состояние выхода внешней команды соответственно. В Procmail есть несколько других подобных условий; возможно, все они довольно неясны.
Новички в сценариях оболочки также должны заметить, что каждый конвейер команд оболочки имеет два отличных результата: все, что выводится на стандартный вывод, и, совершенно отдельно от этого, код выхода который показывает, была ли команда выполнена успешно. (Обычно нулевое состояние выхода означает успех, а все остальное является ошибкой. Например, состояние выхода из grep
равно 0, если он находит хотя бы одно совпадение, 1, если нет, и обычно какой-то другой ненулевой выход код, если вы передали недопустимое регулярное выражение или у вас нет прав на чтение входного файла и т. д. c.)
Дополнительные сведения см. также http://www.iki.fi/era/procmail/ в котором есть старый "мини-FAQ", который охватывает несколько тем здесь, и "краткий справочник" для поиска деталей синтаксиса.
Я не знаком с VirtualMin, но https://docs.virtualmin.com/Webmin/PostgreSQL_Database_Server показывает, как настроить Postgres и в соответствии с https://docs.virtualmin.com/Webmin/Procmail_Mail_Filter Я думаю, вы захотите использовать опцию, чтобы поместить этот код в файл include
.