我们安装了 Postfix,其中有几个虚拟域,每个域都有虚拟用户。这些域和用户使用 mysql 数据库进行映射。到目前为止,我一直通过解析 Postfix 日志文件来跟踪退回。我怀疑一定有更好、更有效的方法来做到这一点。我想到了三种,但我不确定哪种最好:
- 编写一个 Postfix 内容过滤器,记录退回邮件并丢弃邮件
- 使用 procmail - 但我不确定 procmail 如何与没有定义 $HOME 的虚拟用户一起工作
- 编写一个脚本,从邮箱中弹出邮件;解析并记录邮件,然后删除退回的电子邮件
我很想听听您的建议,从维护的角度来看哪种方法最好,从节省服务器资源的角度来看哪种方法最有效。谢谢
答案1
这一切都假设您想要收集有关退回的电子邮件的信息,而不是退回的电子邮件本身:
我对 postfix、mysql 和虚拟主机的设置基本相同。从硬件资源角度来看,跟踪此情况的最有效方法是在执行操作时解析日志文件。但如果您认为解析方式负担过重,则可以使用 Logwatch 等应用程序为您完成所有解析。然后设置 Postfix 以为您丢弃退回的文件。
现在,如果您决定确实要在某处收集这些电子邮件,您可以在 main.cf 文件中使用这些设置:
bounce_notice_recipient = [email protected]
error_notice_recipient = [email protected]
如果你想彻底销毁电子邮件,你可以添加虚拟用户并调整别名文件以将其发送到 dev/null
someone: /dev/null
至于脚本和数据库,我最近经常使用 PHP 和 MySQL,因此如果我要使用这些工具,我可以创建一些 php 代码来读取日志文件,查找退回邮件,然后将它们写入数据库。然后,我会在 mail.log 被截断之前运行代码。事实上,我会在编写代码后在此处发布代码。
如果您想使用 php/mysql 运行它,这里有一些代码(我相信它会更漂亮):
<?php
#parse_logs.php
# load local file into array
$val = file("mail.log");
$pattern = '/status=bounced/';
foreach ($val as &$value) {
if (preg_match($pattern,$value)) {
$a = split('[<>]', $value);
//if you prefer you can also use: preg_match_all('/<(.*)>/', '$value', $matches);
#can be helpful to print the following to the screen during tests
# echo $a[1];
// Make a MySQL Connection
mysql_connect("localhost", "username", "password") or die(mysql_error());
mysql_select_db("postfix_db") or die(mysql_error());
// Insert a row of information into the table "example"
mysql_query("INSERT INTO emails (emailaddress) VALUES('$a[1]') ")
or die(mysql_error());
#again, if you want to see while running manually from cli
#echo "Data Inserted!";
}
#again, if you want to see while running manually from cli
#echo "\n";
}
?>
然后,您可以在 mail.log 设置为回收之前启动一个 cron,或者在 cron 启动后清除日志。
跟踪退回邮件的电子邮件地址似乎需要付出很多努力。当然,您需要编写 mysql 查询才能访问此信息。
您也可以完全跳过 mysql 内容,只需将结果传输到测试文件或电子邮件地址(也可以使用 cron)
php parse.php > results.txt
或者
php parse_logs.php | /usr/sbin/sendmail [email protected]
答案2
我没有示例,因为我从未尝试过,但您可以使用 syslog-ng(取决于您的平台),并创建一个过滤器。过滤器有一个选项可以对消息本身执行正则表达式匹配。您需要做的就是将其发送到特定目的地,该目的地将是 mysql。快速搜索将告诉您如何将 syslog-ng 设置为 mysql,并且一些调整可能会让您获得一个发送到该目的地的过滤器。
答案3
您可以将退回通知通过管道传输到脚本。以下是您可以如何实现它的概述:
/etc/postfix/main.cf
notify_classes = bounce, 2bounce, resource, software
[email protected]
[email protected]
/etc/postfix/transport
[email protected] bouncepipe:
/etc/postfix/master.cf
bouncepipe unix - n n - - pipe
flags=DRhu user=list argv=/etc/postfix/bouncepipe.pl
/etc/postfix/bouncepipe.pl
#!/usr/bin/perl
my $message = '';
my $sender = '';
my $recipient = '';
foreach $line ( <STDIN> )
{
$message .= $line;
chomp( $line );
if ( $line =~ /Final-Recipient: /)
{
my $index = index($line, ';');
$recipient = substr($line, $index+2);
}
if ( $line =~ /X-Postfix-Sender: /)
{
my $index = index($line, ';');
$sender = substr($line, $index+2);
}
}
# Do whatever you need to do with $sender and $recipient