#!/usr/bin/perl use warnings; use strict; use autodie; use Data::Dumper; use Email::Sender::Transport::SMTP::Persistent; use Email::Stuffer; use Encode; use Encode::Locale; use Encode::MIME::Header; use Getopt::Long; use List::Util; use MCE; use MCE::Loop; use Path::Tiny; use Pod::Usage; use Time::HiRes qw(gettimeofday tv_interval); 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; my $chunksize = 1; # #### # 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 $content_html; my $content_txt; my $mce_input; if ($opts{to} =~ m/.+\@.+\..+/) { $mce_input = [$opts{to}]; } else { if (-r $opts{to}) { open my $fh, "<", $opts{to}; $mce_input = $fh; } else { print STDERR "Error: can't read recipient file: $!\n"; } } 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 = path($opts{"content-html"})->slurp_utf8; } $content_txt = path($opts{"content-txt"})->slurp_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}; print "creating workers\n" if $opts{debug}; MCE::Loop::init {max_workers => $thread_count, chunk_size => $chunksize}; print "Sending\n"; my $send_time = [gettimeofday]; mce_loop { my ($mce, $chunk_ref, $chunk_id) = @_; for my $to (@{$chunk_ref}) { $msg->to($to); $msg->send(); print "sent mail in worker ".MCE->wid." from chunk ".$chunk_id."\n" if $opts{debug}; } $transport->disconnect; } $mce_input; 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