最近公司邮件服务器有新的应用,就是在在邮件后面附加类似“免遭声明”之类的声明。只在本地用户发送时和本地用户第一次回复某一主题的时候附加,对于已要附加过声明的邮件,在后面的再回复中不再附加。
搞这个问题搞了一天多了,走了一个大弯路,其实附加声明是很简单的事情,但是判断该主题的邮件是否已经附加过,在这个问题上卡壳了,
原来的思路是:把要附加的内容存储在数据库中。在filter_end中,打开“./INPUTMSG",把经过base64加密的那部分(邮件正文部分)
进行decode。 然后匹配正文中是否已存在特殊字段,如果有,则不再附加,反之,则附加。
但是遇到问题:在解码./INPUTMSG时,只有在重启mimedefang服务后第一次能正确解码,后面再发送其它邮件时,
解码出来的内容都是乱码了。我在打开"./INPUTMSG"时,拷贝一份到其它目录下,然后利用filter_end中
一样的解码过程进行解码,就能够得到正常内容,但是在mimedefang过虑过程中解码得到的却是乱码。
不知道是什么原因,部分代码如下:
- sub filter_end {
- use DBI;
- use MIME::Base64;
- use Encode qw/from_to/;
- my($entity) = @_;
- my ($dsn)="DBI:mysql:database_name:localhost";
- my ($user_name)="username";
- my ($password)="userpassword";
- foreach $recip(@Recipients){
- $recip=~ /<.*@(.*)>/;
- my $domain_to =$1;
- my $localdomain="local_domain";
- my $sign="ANNOUNCEMENT:"; #定义特殊标志,后面匹配到邮件内容中有此字符串时便不在附加
- if($domain_to !~ $localdomain)
- {
- system("/bin/cp ./INPUTMSG /var/spool/MIMEtmp/INPUTMSG"); #拷贝./INPUTMSG到指定目录,然后可以手动解码看看实际内容
- my $file="./INPUTMSG";
- my $body;
- my $start=qr/^Content-Transfer-Encoding: base64/;
- my $end=qr/^--(?!----=_NextPart)/;
- open (FILE,$file) or die "Connot open $!";
- while(<FILE>){
- if((/$start/../$end/) and !/$start/ and !/$end/){
- $body.=$_;
- }
- }
- md_syslog('info',"/$body/'s value is : $body");
- close FILE;
- $de_body=decode_base64("$body");
- md_syslog('info',"/$de_body/'s value is : $de_body");
- if ($de_body !~ $sign)
- {
- $dbh=DBI->connect($dsn,$user_name,$password);
- $sth=$dbh->prepare("SELECT * from comment where active='YES'");
- $sth->execute();
- while(@ary=$sth->fetchrow_array()){
- ($active,$title,$content)=@ary;
- }
- from_to($content,"utf8","gb2312");
- append_text_boilerplate($entity,"$sign"."$content", 0);
- append_html_boilerplate($entity,"<br> <hr> <br>"."$sign"."<br><br>"."$content", 0);
- }
- }
- }
另外,这样做,方法本身可能就有问题,在邮件发送量大的时候,处理延迟问题可能就会很突出,能不能在已经附加过声明的邮件中插入一个标记,这个标记可以终身跟随这一主题的邮件,以后只需要检查邮件中有没有该标记,然后就可以决定是否附加声明了。
后来又去看了一下mimedefang的howto,顺着上面的思路,找到了另种更好的方法:
想想前的打开文件,真不是个什么聪明的方法,现在通过改变邮件的header来实现想要的结果
具体方法:上一封邮件的Message-ID,会现在在回复邮件的References:中,所以我在附加声明之后,修改邮件的Message-ID,在回复时,检查References:中是否含有我指定的Message-ID,如果有,则说明此主题的邮件已经附加过,则不再附加,也不会再修改Message-ID,反之则附加声明
实现代码如下
sub filter_end {
use DBI;
use MIME::Base64;
use Encode qw/from_to/;
my($entity) = @_;
my ($dsn)="DBI:mysql:database_name:localhost";
my ($user_name)="database_user";
my ($password)="database_passwd";
md_syslog('info',"/$recipient/' value is : $recipient"."@Recipients");
foreach $recip(@Recipients){
$recip=~ /<.*@(.*)>/;
my $domain_to =$1;
my $localdomain="local_domain";
my $sign='aaaabbbbccccddddeeeeffff13456789';
if($domain_to !~ $localdomain)
{
my $file="./HEADERS";
open (FILE,$file) or die "Connot open $!";
while(<FILE>){
$header.=$_;
$id=(split(/:/,$_))[1] if(/References:/);
}
md_syslog('info',"/$id/'s value is : $id,,,,,/$sign=$sign");
md_syslog('info',"/$header/'s value is : $header");
close FILE;
if($id !~ $sign)
{
action_change_header("Message-ID", "<$sign>");
$dbh=DBI->connect($dsn,$user_name,$password,{RaiseError => 1});
$sth=$dbh->prepare("SELECT * from comment where active='YES'");
$sth->execute();
while(@ary=$sth->fetchrow_array()){
($active,$create_date,$title,$content)=@ary;
}
from_to($content,"utf8","gb2312");
#md_syslog('info',"/$content/' value is : $content");
append_text_boilerplate($entity,"$sign"."$content", 0);
append_html_boilerplate($entity,"<br> <hr> <br>"."$content", 0);
}
}
}
PS:代码里只是随便指定了一个$sign,这样每封每一次发出去的邮件都有相同的Message-ID,容易被认为是垃圾邮件,你可以采取一些简单的方法,生成不同的Message-ID,方法这里不再细说