简体   繁体   English

有什么方法可以通过获取“来自”并将其与数据库匹配来动态过滤 email? (使用 procmail 或 Virtualmin 或 Webmin)

[英]Any way to filter email dynamically by taking 'from' and matching it with database ? (Using procmail or Virtualmin or Webmin)

I basically want to check the incoming 'From' in the email received and then either我基本上想检查收到的 email 中的传入“发件人”,然后

  1. Keep it and make it deliver to the intended mailbox if the email matches a Specified MySQL/PostgreSQL Database User (eg. select email from users where exists ('from email address') ) Keep it and make it deliver to the intended mailbox if the email matches a Specified MySQL/PostgreSQL Database User (eg. select email from users where exists ('from email address') )

  2. If the 'From' address is blank or it is not found in the database, the email should be discarded如果“发件人”地址为空或在数据库中未找到,则应丢弃 email

Any way I can achieve this before the e-mail is delivered to the intended mailbox?在将电子邮件传递到预期邮箱之前,我有什么办法可以做到这一点?

I am using Procmail + Virtualmin + Webmin + PostgreSQL我正在使用 Procmail + Virtualmin + Webmin + PostgreSQL

PS: I want to apply this filter not to the wole server but to some specified mailboxes/users (i'm assuming 1 user = 1 mailbox here) PS:我不想将此过滤器应用于 wole 服务器,而是应用于某些指定的邮箱/用户(我假设 1 个用户 = 1 个邮箱)

Procmail can easily run an external command in a condition and react to its exit status. Procmail 可以轻松地在条件下运行外部命令并对其退出状态做出反应。 How exactly to make your particular SQL client set its exit code will depend on which one you are using;如何让您的特定 SQL 客户端设置其退出代码将取决于您使用的是哪一个; perhaps its man page will reveal an option to make it exit with an error when a query produces an empty result set, for example?例如,当查询产生空结果集时,它的man页可能会显示一个选项以使其退出并出现错误? Or else write a shell wrapper to look for empty output.或者写一个 shell 包装器来寻找空的 output。

A complication is that Procmail (or rather, the companion utility formail ) can easily extract a string from eg the From: header;一个复杂的问题是 Procmail (或者更确切地说,配套实用程序formail )可以轻松地从例如From: header; 中提取字符串。 but you want to reduce this to just the email terminus.但是您想将其减少到 email 总站。 This is a common enough task that it's easy to find a canned solution - generate a reply and then extract the To: address (sic.) from that.这是一个很常见的任务,很容易找到一个固定的解决方案——生成一个回复,然后从中提取To:地址(原文如此。)。

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
}

The first condition examines the variable and succeeds if it contains one of the addresses (my original answer simply had the regex . which matches if the string contains at least one character, any character; I'm not convinced this is actually necessary or useful; there should be no way for From: to be empty).第一个条件检查变量并在它包含一个地址时成功(我的原始答案只是有正则表达式.如果字符串包含至少一个字符,任何字符,则匹配;我不相信这实际上是必要或有用的; From:应该没有办法为空)。 If it is true, Procmail enters the braces;如果为真,Procmail 进入大括号; if not, they will be skipped.如果没有,它们将被跳过。

The first recipe inside the braces runs an external command and examines its exit code.大括号内的第一个配方运行一个外部命令并检查其退出代码。 I'm imagining your SQL client is called yoursql and that it has options to turn off human-friendly formatting (table headers etc) and for running a query directly from the command line on a specific database.我想象您的 SQL 客户端称为yoursql ,它具有关闭人类友好格式(表头等)和直接从特定数据库上的命令行运行查询的选项。 We use double quotes so that the shell will interpolate the variable FROM before running this command (maybe there is a safer way to pass string variables which might contain SQL injection attempts with something like --variable from="$FROM" and then use that variable in the query? See below.)我们使用双引号,以便 shell 将在运行此命令之前插入变量FROM (也许有一种更安全的方法来传递可能包含 SQL 注入尝试的字符串变量,例如--variable from="$FROM"然后使用它查询中的变量?见下文。)

If there is no option to directly set the exit code, but you can make sure standard output is completely empty in the case of no result, piping the command to grep -q.如果没有直接设置退出码的选项,但是可以确保标准的 output 在没有结果的情况下完全为空,将命令传递给grep -q. will produce the correct exit code.将产生正确的退出代码。 In a more complex case, maybe write a simple Awk script to identify an empty result set and set its exit status accordingly.在更复杂的情况下,可以编写一个简单的 Awk 脚本来识别空结果集并相应地设置其退出状态。

Scraping together information from https://www.postgresql.org/docs/current/app-psql.html , How do you use script variables in psql?https://www.postgresql.org/docs/current/app-psql.html中抓取信息, 如何在 psql 中使用脚本变量? , Making an empty output from psql , and from your question, I end up with the following attempt to implement this in psql ; 从 psql 制作一个空的 output ,根据您的问题,我最终尝试在psql中实现此功能; but as I don't have a Postgres instance to test with, or any information about your database schema, this is still approximate at best.但由于我没有要测试的 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 .

(We still can't use single quotes around the SQL query, to completely protect it from the shell, because Postgres insists on single quotes around :'from' , and the shell offers no facility for embedding literal single quotes inside single quotes.) (We still can't use single quotes around the SQL query, to completely protect it from the shell, because Postgres insists on single quotes around :'from' , and the shell offers no facility for embedding literal single quotes inside single quotes.)

The surrounding Procmail code should be reasonably self-explanatory, but here goes anyway.周围的 Procmail 代码应该是不言自明的,但无论如何。 In the first recipe inside the braces, if the condition is true, the empty braces in its action line are a no-op;在大括号内的第一个配方中,如果条件为真,则其操作行中的空大括号是无操作的; the E flag on the next recipe is a condition which is true only if any of the conditions on the previous recipe failed.下一个配方上的E标志是一个条件,仅当前一个配方上的任何条件失败时才为真。 This is a common idiom to avoid having to use a lot of negations;这是避免使用大量否定的常用习语; perhaps look up "de Morgan's law".也许查一下“德摩根定律”。 The net result is that we discard the message by delivering it to /dev/null if either condition in the first recipe failed;最终结果是,如果第一个配方中的任一条件失败,我们通过将消息传递到/dev/null来丢弃消息; and otherwise, we simply pass it through, and Procmail will eventually deliver it to its default destination.否则,我们只是简单地传递它,Procmail 最终会将它传递到它的默认目的地。

The recipe was refactored in response to updates to your question;配方已根据您对问题的更新进行了重构; perhaps now it would make more sense to just negate the exit code from psql with a !也许现在用!来否定psql的退出代码会更有意义。 in front:在前:

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

Tangentially, perhaps notice how Procmail's syntax exploits the fact that a leading ?切线,也许注意到 Procmail 的语法如何利用前导? or a doubled ??还是翻倍?? are not valid in regular expressions.在正则表达式中无效。 So the parser can unambiguously tell that these conditions are not regular expressions;所以解析器可以明确地告诉这些条件不是正则表达式; they compare a variable to the regex after ??他们在??之后将变量与正则表达式进行比较, or examine the exit status of an external command, respectively. ,或分别检查外部命令的退出状态。 There are a few other special conditions like this in Procmail; Procmail 中还有一些其他类似的特殊条件; arguably, all of them are rather obscure.可以说,所有这些都相当晦涩难懂。

Newcomers to shell scripting should also notice that each shell command pipeline has two distinct results: whatever is being printed on standard output, and, completely separate from that, an exit code which reveals whether or not the command completed successfully. shell 脚本的新手还应该注意到,每个 shell 命令管道都有两个不同的结果:在标准 output 上打印的任何内容,显示命令是否成功完成,以及退出代码是否完全分开。 (Conventionally, a zero exit status signals success, and anything else is an error. For example, the exit status from grep is 0 if it finds at least one match, 1 if it doesn't, and usually some other nonzero exit code if you passed in an invalid regular expression, or you don't have permission to read the input file, etc.) (通常,零退出状态表示成功,其他任何内容都是错误。例如,如果grep找到至少一个匹配项,则退出状态为 0,如果没有,则通常为 1,并且通常一些其他非零退出代码如果您传入了无效的正则表达式,或者您没有读取输入文件的权限等)

For further details, perhaps see also http://www.iki.fi/era/procmail/ which has an old "mini-FAQ" which covers several of the topics here, and a "quick reference" for looking up details of the syntax.有关更多详细信息,也许另请参阅http://www.iki.fi/era/procmail/它有一个涵盖此处几个主题的旧“迷你常见问题解答”,以及用于查找详细信息的“快速参考”句法。

I'm not familiar with Virtualmin but https://docs.virtualmin.com/Webmin/PostgreSQL_Database_Server shows how to set up Postgres and as per https://docs.virtualmin.com/Webmin/Procmail_Mail_Filter I guess you will want to use the option to put this code in an include file.我对 Virtualmin 不熟悉,但https://docs.virtualmin.com/Webmin/PostgreSQL_Database_Server显示了如何设置 Postgres 并按照https://docs.virtualmin.com/Webmin/Procmail_Mail_Filter我猜你会想要使用将此代码放入include文件中的选项。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 有没有办法使用匹配子句在 json postgres 列中搜索? - Is there any way to search in json postgres column using matching clause? 有没有办法从数据库中加载部分表? - Is there any way to load part of table from DataBase? 在我们使用行过滤的 where 条件下,有什么方法可以对其进行索引吗? - Within the where condition we filter using row, Is there any way to index on it? 有没有办法解开 heroku 数据库 - is there any way to unfork heroku database 使用R dplyr从redshift数据库过滤表 - Filter table from redshift database using R dplyr 是否有独立于数据库的方法来按“无”/“NaN”进行过滤? - Is there a database independent way to filter by "None"/"NaN"? 有没有办法从 NestJS 框架中的模块文件访问数据库相关的东西? - Is there any way to access the database related stuff from a module file in NestJS framework? 有什么方法可以判断数据库行是否有约束? - Is there any way to tell if a database row has constraints? 使用 Rails 显示来自数据库的图像的最简单方法 - Simplest way to display image coming from database using Rails Postgresql:有没有办法从PGDATA / base目录读取并将数据导入新数据库? - Postgresql: Is there any way to read from a PGDATA/base directory and import the data to a new database?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM