->
继使用 perl 发中文标题邮件,和中文附件邮件后,又把他们整合了一下写了一个 pm 干这个事。
其实发带附件的邮件应该是有现成的 pm 干这个事的,比如 MIME::Lite 之类,没特殊需求还是用那个吧,这个纯属无聊写的。
文件前面有使用方法。。
package SendMail;
use strict;
use warnings;
use Data::Dumper;
use Encode;
use MIME::Base64;
=head1 Examples
use SendMail;
my $sm = SendMail->new( {
To => 'you@foo.com, other@bar.com',
Subject => 'just a test 中文',
});
-- or --
my $sm = SendMail->new( {
From => 'me@abc.com',
To => 'you@foo.com, other@bar.com',
Subject => 'just a test 中文',
} );
-- or --
my $sm = SendMail->new( {
From => 'me@abc.com',
To => 'you@foo.com, other@bar.com',
Cc => 'cc@foobar.com',
Subject => 'just a test 中文',
} );
$sm->attach( {
Type => "text/plain",
Data => "只是一个测试..a test"
});
$sm->attach( {
Type => 'application/octet-stream',
Filename => 'test 中文.txt',
Data => "只是一个 test ..."
});
$sm->test;
-- or --
$sm->send;
=cut
use vars qw($VERSION);
$VERSION = '0.01';
our $boundary = "FFFFFFFFKKKKKK";
our $from = 'no-reply@abc.com';
our $subject = "No subject";
our $to;
our $cc;
our @body;
sub new {
my $package = shift;
my $info = shift;
$subject = $info->{Subject} || $subject;
$subject = encode('MIME-B', decode('utf8', $subject));
$from = $info->{From} || $from;
$to = $info->{To} || die "Need to set MailTo 'To'!";
$cc = $info->{Cc} || "";
push @body, "MIME-Version: 1.0";
push @body, "Content-Type: multipart/mixed; boundary=\"$boundary\"";
push @body, "";
return bless( {}, $package);
}
sub attach {
my $self = shift;
my $f_hash = shift;
die "Need data when attach!" if ( not defined $f_hash->{Data} );
my $type = "text/plain";
$type = $f_hash->{Type} if defined $f_hash->{Type};
my @t;
push @t, "--$boundary";
if ( $type eq "text/plain" ) {
push @t, "Content-Type: $type; charset=utf-8";
} else {
my $filename = "file1.txt";
$filename = encode('MIME-B', decode('utf8', $f_hash->{Filename})) if defined $f_hash->{Filename};
push @t, "Content-Type: $type";
push @t, "Content-Disposition: attachment; filename=$filename";
}
push @t, "Content-Transfer-Encoding: base64";
push @t, "";
push @t, encode_base64($f_hash->{Data});
push @body, @t;
}
sub send {
my $self = shift;
open(my $fh, '|/usr/sbin/sendmail -t');
$self->print_to($fh);
close($fh);
}
sub print_to {
my $self = shift;
my $fh = shift;
push @body, "--$boundary--";
print $fh "From: $from\r\n";
print $fh "To: $to\r\n";
print $fh "Cc: $cc\r\n" if $cc;
print $fh "Subject: $subject\r\n";
for ( @body ) {
print $fh "$_\r\n";
}
}
sub test {
my $self = shift;
open ( my $fh, '>-');
$self->print_to($fh);
close($fh);
}
1;
->
继 上篇 使用 perl 发带中文标题的邮件后,又研究了下发带附件的。
基本差别不大,主要是那个 Content-type 要变一下。那个 boundary 可以自己随便写,和后面的统一就行了。
my $title = encode_base64("标题", "");
my $body = encode_base64("邮件正文");
my $attach = encode_base64("附件内容");
my $filename = encode('MIME-B', decode('utf8', "文件中文.txt"))
open(MAIL, '|/usr/sbin/sendmail -t');
print MAIL "From: test\@abs.com\r\n";
print MAIL "To: test\@abs.com\r\n";
print MAIL "Subject: =?UTF-8?B?$title?=\r\n";
print MAIL "MIME-Version: 1.0\r\n";
# print MAIL "Content-type: text/plain; charset=utf-8\r\n";
print MAIL <<EOF;
Content-Type: multipart/mixed; boundary=\"FFFFFFFFKKKKKK\"
--FFFFFFFFKKKKKK
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: base64
$body
--FFFFFFFFKKKKKK
Content-Type: application/octet-stream
Content-Disposition: attachment; filename=$filename.csv
Content-Transfer-Encoding: base64
$attach
--FFFFFFFFKKKKKK--
EOF
close(MAIL);
->
代码如下面,解决乱码的方法是使用 base64 编码。
use MIME::Base64::Perl;
open(MAIL, '|/usr/sbin/sendmail -t');
my $recver = 'wangdong@abc.com';
my $alertTitle = "中文 asdfsdf sdfsdf sdf sdf s df sd fsd f sd fsd f sdf sdf sdf";
my $alertText = "body ";
my $encoded = encode_base64($alertTitle, "");
print MAIL "From: alert\@abc.com\r\n";
print MAIL "To: $recver\r\n";
print MAIL "Subject: =?UTF-8?B?" . $encoded . "?=\r\n";
print MAIL "MIME-Version: 1.0\r\n";
print MAIL "Content-type: text/plain; charset=utf-8\r\n";
print MAIL "\n";
print MAIL "$alertText";
close(MAIL);
这里面 encode_base64 可以把文本做 base64 编码,要注意的是这个方法的第二个参数,是用来把编码结果进行格式化的,会每 76 个字符插入一个这个参数,默认是换行。
如果不是 utf8 的文本,那把里面的 utf8 改一下就好了。
命令行下面发送邮件比较简单,恐怕都会使用。
$ echo "hello .. " | mail -s subject xxx@abc.com
$ cat /path/to/file | mail -s subject xxx@abc.com
$ mail -s subject xxx@abc.com << EOF
hi
the end..
EOF
上面这些方法都可以发送邮件。还有一种方法。
$ cat a.txt
Subject: test
From: xxx@abc.com
To: xxx@abc.com
hi
sdfsdfsdf
the end.
$ cat a.txt | sendmail -t
这样可以把邮件头信息写到文件里面的,你也可以用 php,perl 来打印类似的信息给 sendmail -t ,让他来发。
那么如果有附件应该怎么办?可以使用 uuencode。
$ uuencode a.txt a.txt | mail -s test xxx@abc.com
$ (cat a.txt; uuencode b.txt b.txt; cat c.txt) |sendmail -t
应该说的很明白了吧?
sendmail有个 /etc/aliases 配置文件,在里面可以给某个帐号设置alias,这样给这个alias发的邮件,都会给设置好的用户转发过去。要知道sendmail的帐号是和系统帐号联系在一起的,添加mail帐号得给系统添加帐号(qmail可以实现虚拟用户,或许sendmail也可以,而我不知道罢了)。而这个alias帐号却不是必须有得有系统帐号的,只要设置了alias,就可以给alias用户发邮件,就好像系统真有这么一个帐号一样。
关于 /etc/aliases 文件,这里有个文章有说明。下面复制几个例子。
# RFC 822 规定每个域名都需要有一个 "postmaster"
postmaster : root
# 将 postmaster 的邮件都转发给 root 帐号,当然你下面还可以将root帐号的邮件在转发给别人。
# 转发也可以转发到文件
# 比如这个,都说了nobody了还给发邮件,邮件都丢掉
nobody : /dev/null
# 也可以通过管道作为另一个程序的输入
# 比如给procmail,它能实现的功能可就多了,比如可以根据邮件大小转发到不同的用户,或者调用spamassian、clamav来查垃圾邮件和病毒等
# 一个自动的bug跟踪程序
program-bugs: |/usr/local/bin/program-bug-tracker
# 也可以转发到多个帐号,用逗号分隔就可以
project-list: johndoe@host1.uiuc.edu,jsmith@host2.uiuc.edu,someone@host.purdue.edu
可以看到功能还是很强悍的,尤其是可以 pipe 到程序,procmail、maildrop都是很不错的过滤程序,能实现很多其他的功能。
标题的要求是“抄送”某个帐号的邮件给别的用户,有点类似监控的意思。怎么实现呢?可能第一个想到的就是类似下面这种方法:
somebody:other1,other2,somebody
这样是不是就能实现抄送呢?这样会造成死循环,呵呵。
看样子似乎只能通过pipe到程序实现了,看procmail、maildrop的文档还不够头疼的。其实还有个简单的方法,就是 .forward 文件。
.forward 文件位于用户的 home 下面,权限是 600 。他的功能和 /etc/aliases 文件类似,不过是 aliases 文件只能由root用户来修改,而 .forward 文件用户自己就可以修改。除了上面aliases能做到的事情外,他还多了一个功能,就是标题要求的功能。
按照标题的要求,只需要在 somebody 用户的 .forward 文件中放入下面的内容就可以了。
要注意 somebody 前面的那个\,就是用来防止转发死循环的。加了\之后,给somebody转发的时候会忽略该用户的 .forward 文件。
近期评论