From 1812d700df5b1661f08daa0213fc4ac48e78f99b Mon Sep 17 00:00:00 2001 From: Florian Pritz Date: Sat, 23 May 2015 16:42:35 +0200 Subject: Add mailer.pl Signed-off-by: Florian Pritz --- mailer.pl | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 mailer.pl (limited to 'mailer.pl') diff --git a/mailer.pl b/mailer.pl new file mode 100644 index 0000000..d016673 --- /dev/null +++ b/mailer.pl @@ -0,0 +1,155 @@ +#!/usr/bin/perl +use warnings; +use strict; +use Email::Stuffer; +use Email::Sender::Transport::SMTP::Persistent; +use File::Basename; +use Encode; +use Encode::Locale; +use File::Slurp; +use threads; +use Thread::Queue; +use Getopt::Long; +use Pod::Usage; +use Encode::MIME::Header; +use Time::HiRes qw(gettimeofday tv_interval); +use Data::Dumper; + +use open ':encoding(locale)'; +@ARGV = map { decode(locale => $_, 1) } @ARGV; + +# #### +# configurable settings +# #### + +my $transport = Email::Sender::Transport::SMTP::Persistent->new({ + host => 'localhost', + port => 25, + #debug => 1, +}); +my $thread_count = 64; + +# #### +# end config +# #### + +my %opts = (); + +Getopt::Long::Configure ("bundling"); +pod2usage(-verbose => 0) if (@ARGV== 0); +GetOptions(\%opts, "help|h", "to=s", "from=s", "subject=s", "content-html=s", "content-txt=s", "debug") or pod2usage(2); +pod2usage(0) if $opts{help}; + +sub trim { + my $string = shift; + $string =~ s/^\s+//; + $string =~ s/\s+$//; + return $string; +} + +my $subject = $opts{subject}; +my $from = $opts{from}; +my @addrlist; +my $content_html; +my $content_txt; + +if ($opts{to} =~ m/.+\@.+\..+/) { + push @addrlist, $opts{to}; +} else { + if (-r $opts{to}) { + open LIST, "<", $opts{to} or die; + for () { + my $to = trim($_); + next if ($to eq ""); + push @addrlist, $to; + } + close LIST; + } else { + print STDERR "Error: can't read recipient file: $!\n"; + } +} + +if (0+@addrlist < $thread_count) { + $thread_count = 0+@addrlist; +} + +die "Error: subject not set\n" unless ($opts{subject}); +die "Error: from not set\n" unless ($opts{from}); +die "Error: content-txt not set\n" unless ($opts{"content-txt"}); +die "Error: can't read content-txt: $!\n" unless (-r $opts{"content-txt"}); +die "Error: can't read content-html: $!\n" if ($opts{"content-html"} and not -r $opts{"content-html"}); + +if ($opts{"content-html"}) { + $content_html = read_file($opts{"content-html"}, binmode => ':utf8'); +} +$content_txt = read_file($opts{"content-txt"}, binmode => ':utf8'); + +print "Building email ... " if $opts{debug}; + +# create mail +# To will be filled when sending +my $msg = Email::Stuffer->new(); +$msg->from($from); +$msg->subject(trim($subject)); +$msg->text_body($content_txt); +$msg->html_body($content_html); +$msg->header("Precedence", "bulk"); +#$msg->header("List-Unsubscribe", ""); +$msg->transport($transport); + +print "done\n" if $opts{debug}; + +my $q = Thread::Queue->new(); + +print "creating worker threads\n" if $opts{debug}; +for (my $i = 0; $i < $thread_count; $i++) { + my $thr = threads->new(sub { + while (my $to = $q->dequeue()) { + $msg->to($to); + $msg->send(); + print "sent mail in thread".threads->self->tid()."\n" if $opts{debug}; + } + $transport->disconnect; + }); +} + +print "Sending\n"; + +my $send_time = [gettimeofday]; + +for (@addrlist) { + $q->enqueue($_); +} + +$q->end(); + +# wait for everyone before exiting +foreach my $thr (threads->list) { + if ($thr->tid && !threads::equal($thr, threads->self)) { + print "waiting for thread ".$thr->tid()." to finish\n" if $opts{debug}; + $thr->join; + } +} + +print "done after ".tv_interval($send_time)." seconds\n"; + +__END__ + +=head1 NAME + +mailer.pl - send lots of mails + +=head1 SYNOPSIS + +mailer.pl options ... + + Options: + --help, -h short help message + --to recipient(s) + --from from + --subject subject + --content-html body of the mail (html part) (optional) + --content-txt body of the mail (text part) + --debug output extra debug information + +=cut -- cgit v1.2.3-24-g4f1b