#!/usr/bin/perl -w use strict; use Carp qw(croak); $|++; our $Debug = 3; our $Verbose = 2; my $MAILER = "/usr/sbin/sendmail -t"; sub die_nicely { local $\ = "\n"; print STDERR foreach(@_); exit(1); } sub valid { foreach(@_) { return 0 unless /^.+\@.+\.\w{2,4}$/i } 1; } sub slurp($) { local $/ = undef; open(FILE, "<${_[0]}") or die "cannot open file $_[0] ($!)"; my $contents = ; close(FILE); $contents; } sub lines($) { local $_ = slurp($_[0]); ($_ = y/\n/\n/); } sub mail { my($From, $To, $Subject, $Body, $Headers) = @_; defined $Body or croak "Required argument was not supplied"; open(MAIL, "|$MAILER") or die_nicely "Failed to open mailer, where is it?\n"; $To = join ', ', @$To if(ref $To eq 'ARRAY'); print MAIL "From: $From\n", "To: $To\n", "Subject: $Subject\n"; print MAIL foreach(@$Headers); print MAIL "Content-Type: text/html\n\n"; print MAIL $Body; close(MAIL) or warn "Mailer did not exit nicely ($!)", return; # Subject: A relevant subject line } my $NoFork = 0; my %EXPECT = ( body => 1, subject => 1, from => 1, max => 1, rmax => 1, debug => 0, verbose => 0, nofork => 1 ); #massmail.pl -from your@host.com [-body ] [-subject ] [-rmax ] [-max <#emails#>:<#per sec#>] [-verbose] [-debug] -- # assign defaults my $OPT = { body => 'body.txt', subject => 'subject.txt', max => '25:0', rmax => 25, debug => 0, nofork => 0, verbose => 1 }; ARG: while((local $_ = lc $ARGV[0]) =~ /^-/) { shift; last ARG if /^--$/; s/^-{1,2}//; $OPT->{$_} = 1, next ARG unless $EXPECT{$_}; $OPT->{$_} = shift; } not scalar grep {!exists $EXPECT{$_}} keys %$OPT or die_nicely "Unknown argument suppled (--help?)"; $NoFork = 1 if $^O =~ /mswin/i; # regardless of what is sent $Verbose = 1 unless exists $OPT->{verbose}; die_nicely "Required argument 'from' was not supplied" unless($OPT->{from}); do { print "OPT: $_\t=>\t$OPT->{$_}\n" foreach(keys %$OPT); print "ARGV: $_\n" foreach(@ARGV); print "\$Debug = $Debug\n"; print "\$Verbose = $Verbose\n"; } if $Debug; die_nicely "Invalid parameter supplied for argument 'max', should be :" unless $OPT->{max} =~ /^\d+:\d+$/; my($LIMIT, $DELAY) = split /:/, $OPT->{max}; $LIMIT ||= 25; my $Body = slurp($OPT->{body}); (my $Subject = slurp($OPT->{subject})) =~ s/[\r\n]//g; print $Body; print "\n\n\n\n\n", $Subject . "\n"; do { local $, = "\n"; print "\n - Subject:\t(" . ((defined $Subject) ? $Subject : 'No Subject') . ") <" . $OPT->{subject} . ">", " - Body (HTML):\t" . $OPT->{body}, " - Emails:\t" . join(", ", @ARGV) . "\n"; printf("\n - Operating at an interval of %d sec%s, %d emails per.\n\n", $DELAY, ($DELAY == 1) ? '' : 's', $LIMIT); }; my($TOTAL, $MAILS, $BEGUN) = (0, 0, time); FILE:foreach my $file (@ARGV) { print "\n -- Moving onto file '$file'.."; open(DICT, "<$file") or die_nicely "\n\nCannot open file '$file' ($!)"; my($valid, $invalid, $c) = (0) x 3; PIECE:{ my($num, @addrs) = ($OPT->{rmax}, ()); print " reading...\n\n"; my @badlines = (); EMAIL:while($c++, chomp(local $_ = )) { $invalid++, print "\nSKIPPING $_\n", next EMAIL unless valid($_); chomp(local $_ = ), push(@addrs, $_), $valid++ while(!eof(DICT) && $num--); $MAILS++; print " - Mailing 1 item, to a total of " . scalar @addrs . " address(es). Total emails queued thus far, " . $MAILS . "\n" if($Verbose >= 1); print "\nAddresses: (" . join(", ", @addrs) . ")\n\n" if($Verbose > 1); if((defined $DELAY && $DELAY =~ /^\d+$/) && ($Verbose >= 2) && ($DELAY > 0)) { print " zZzz.. Sleeping.. zZzz.. $DELAY sec(s)\n\n"; sleep($DELAY); } } continue { $num = $OPT->{rmax}; @addrs = (); $c++; } $TOTAL += $valid + $invalid; # print "\n\$c=$c\n\$TOTAL=$TOTAL\n\$valid=$valid\n\$invalid=$invalid\n\n" if $Debug; } } print "Queued $MAILS Emails, to a total of $TOTAL addresses, in " . (time() - $BEGUN) . " sec(s)\n\nExiting..."; sleep(2), print " Done!\n"; exit(0); 1; __END__