#!/usr/bin/perl -w use strict; use Net::SMTP; #part of standard Perl distro # brunch-spam.pl, written by philg@mit.edu, william.crawford@gmail.com December 2004 # based on https://ryantate.com/massmail.pl.txt # Database format is: # email|full name|affiliation note|keywords space-separated # Everything optional except email. # Examples: # george.w.bush@aya.yale.edu|George W. Bush|smartest Yale grad ever|politics drinking iraq iraq iraq # john.f.kerry@aya.yale.edu|||leisure rich-babes yachting mansions # billg@microsoft.com # Parameters my $return_email_address = '*** put your email address here ***'; my $return_full_name = "*** put your name here ***"; my $smtp_server= "*** put your smtp server here ***"; # Open SMTP interface # detect bad server specification quickly and die my $smtp = Net::SMTP->new($smtp_server) or die "Could not connect to SMTP server $smtp_server: $!"; # Prompt for database file, message file, subject line, keywords print "Enter database file name: "; my $address_file = ; chomp($address_file); #Open files right away to quickly detect typos open ADDYS, "<$address_file" or die "Could not open addressfile: $!"; print "Enter message file name: "; my $message_file = ; chomp($message_file); open MESSAGE, "<$message_file" or die "Could not open messagefile: $!"; my $message = join('',); #Slurp in the whole message file close MESSAGE or die "Could not close messagefile: $!"; print "Enter subject line: "; my $subject_line = ; chomp($subject_line); print "Enter include-only keywords, space-separated (only those people flagged with at least one of these keywords will be invited): "; my $include_keywords = ; chomp($include_keywords); my %include_keywords = map {lc $_ => 1} (split /\s+/, $include_keywords); print "Enter exclude keywords, space-separated (anyone flagged with this keyword will NOT be invited): "; my $exclude_keywords = ; chomp($exclude_keywords); my %exclude_keywords = map {lc $_ => 1} (split /\s+/, $exclude_keywords); my @addresses; while () { chomp; next unless $_; #allow blank lines in addressfile # now must split by | to get the fields, backslash because | is special sep char for regexp my ($email_address, $name, $affiliation, $keywords) = split /\|/; my @keywords = $keywords ? split /\s+/, $keywords : (); $email_address = "$name <$email_address>" if $name; # Decide if we can include this address in our mailing: # 1a. If there are no include keywords, proceed to 2, # since everyone is included in case of no include keywords. # 1b. If there are include keywords for this mailing, run each # keyword for this address through a hash of include keywords, # looking for a match, in which case proceed to 2. # 2. Finally, run each keyword for this address through # a hash of exclude keywords for this mailing and make sure it does not match # 3. Assuming 2 is successful, add to mailing list. # Now the code, in one (logical) line: push @addresses, $email_address if ((not keys %include_keywords) || grep {$include_keywords{lc $_}} @keywords) && not (grep {$exclude_keywords{lc $_}} @keywords); } close ADDYS or die "Could not close addressfile: $!"; # let's solicit confirmation from the user print "\n\nPreparing to send a message of the following form... Subject: $subject_line Message: $message ----------------- To the following folks "; print join(', ', @addresses); print "\n\nConfirm with y or abort with n: "; die "aborted" unless =~ /y/i; #Send messages my $address_count = 0; foreach my $address (@addresses) { $smtp->mail($return_email_address) or die $!; $smtp->to($address) or die $!; $smtp->data() or die $!; $smtp->datasend("From: $return_full_name <$return_email_address>\n") or die $!; $smtp->datasend("To: $address\n") or die $!; $smtp->datasend("Subject: $subject_line\n") or die $!; $smtp->datasend("\n") or die $!; $smtp->datasend($message) or die $!; $smtp->dataend() or die $!; $address_count++; } $smtp->quit or die $!; print "Sent $address_count messages.\n";