Любой способ динамически фильтровать электронную почту, беря «из» и сопоставляя его с базой данных? (Используя procmail или VirtualMin или Webmin) - PullRequest
0 голосов
/ 01 мая 2020

Я в основном хочу проверить входящее «От» в полученном письме, а затем либо:

  1. Сохраните его и сделайте так, чтобы оно доставлялось в предполагаемый почтовый ящик, если электронное письмо соответствует указанному MySQL / PostgreSQL Пользователь базы данных (например, выберите адрес электронной почты от пользователей, где существует («с адреса электронной почты»))

  2. Если адрес «От» пуст или не найден в базе данных , электронная почта должна быть отброшена

Как я могу добиться этого до того, как электронная почта будет доставлена ​​в нужный почтовый ящик?

Я использую Procmail + Virtualmin + Webmin + PostgreSQL

PS: я хочу применить этот фильтр не к отдельному серверу, а к некоторым указанным почтовым ящикам / пользователям (я предполагаю, что 1 пользователь = 1 почтовый ящик здесь)

1 Ответ

0 голосов
/ 01 мая 2020

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.

...