From: "Rick Williams" <rick@charlesworth.com>
Date: Wed, 12 May 1999 09:16:02 +0100

I was asked for a copy of the programs we were using to mail 
everybody and as they are not too big I hope you don't mind me 
posting them here. There are two programs emailrequest.pl and  
post_all.pl, they both require Mail.pm which I understand is 
generally available.

These programs have been completely re-written from scratch by 
one of our programmers and work <G>. The usual disclaimers 
apply. 

emailrequest.pl generates a list of all current users from the 
password list sorted on company, surname and firstname, this is 
very useful for us here because our staff constantly changes. The 
other, post_all.pl takes a message and sends it on to all users in 
the password list as a BCC, there are certain filters in the program 
to miss out non-human users.

You will need some settings in your aliases file to call these 
programs (although rather obvious). The first setting is needed.

### Alias File ###
discard:	:blackhole:

#email list request
email:		"|/where/you/put/it/emailrequest.pl"

#mail to everyone
everyone:	"|/where/you/put/it/post_all.pl"

#If you want to send a mass message to one part of your org only
#and it is defined in the company setting in the password file
#then use
company:	"|/where/you/put/it/post_all.pl \"Company Section\""


--Message-Boundary-12668
Content-description: Text from file 'emailrequest.pl'

#!/usr/bin/perl
#
#
#  Internal EMail List Generator
#
#  Version 2.0
#
#  William F. McCaw  1999
#
#
#  Returns an email containing a sorted list of all valid users on the
#  system, grouped according to company.
#
#  For this program to work properly, the following conditions must be met
#  for all valid email recipients...
#
#  * Their UID must be between 1000 and 60000 (inclusive).
#  * Their Name must be defined.
#  * Their Name must not start with a lower case 'x'.
#  * Their Name must not be 'nobody'.
#  * Their must be of the following format...
#
#       "Forename Surname, Company"
#
#    Note... The ", Company" must be present.
#            Forename is assumed to be the first word.
#            Surname is assumed to be everything else.
#


#
# Read the message from standard input
#
$MsgSender = '';
# Extract the required details from the message's header
while ( defined($Line = <STDIN>) && ($Line =~ /^[^\r\n]/) )
   {
   $Line =~ s/[\r\n]//gs;
   if ( $Line =~ /^Return-Path:\s*<([^>]+)>/i )     # First choice for sender
      { $MsgSender = $1; }
   if ( $Line =~ /^From:\s*(.*)/i && !$MsgSender )  # May be no return path
      { $MsgSender = $1; }
   }
# Ensure we have a sender's address
exit(0) if ( !$MsgSender );

#
# Read the contents of the system's password file
#
open(PASS, '/etc/passwd') || exit(0);
@Users = <PASS>;
close(PASS);

#
# Extract the details of all valid users from the password file and batch
# them according to the company name associated with them.
#
%Companies = ();
foreach $User ( @Users )
   {
# Separate the current user's details and determine whether to include them
# within the generated email list
   ( $EMail, $Password, $UID, $GID, $Name, $Home, $Shell ) = split(/:/, $User);
   next if ( !defined($UID) || ($UID < 1000) || ($UID > 60000) ||
             !defined($Name) || ($Name =~ /^x/) || ($Name eq 'nobody') );
# Ensure the name field contains a company name
   next if ( !($Name =~ /^(.*?)\s*\,\s*(.*?)$/) );
   $Name = $1;
   $Company = $2;
# Get the reference to the members array for this company, creating the
# company entry as and when required
   if ( exists($Companies{uc($Company)}) )
      { $Members = $Companies{uc($Company)}->[1]; }
   else
      {
      $Members = [];
      $Companies{uc($Company)} = [ $Company, $Members ];
      }
# Massage the user's name into the required "Surname, Forename" format
   if ( $Name =~ /^\s*([^\s]+)\s+(.+)$/ )
      { $Name = "$2, $1"; }
# Append the user to the list for the current company
   push(@$Members, [ $Name, $EMail ]);
   }

#
# Generate the email back to the original sender containing the full list
#
open(MAIL, "|/usr/bin/exim -t");
#
# Output the message headers and leading message body text
print(MAIL "From: $MsgSender\n",
           "To: $MsgSender\n",
           "Subject: Requested EMail List\n\n",
           "Internal EMail addresses as of: ", scalar(localtime()), "\n");
#
# Output the sorted list of companies, and within that, output the sorted
# list of individuals within that company
foreach $Company ( sort(keys(%Companies)) )
   {
   $Company = $Companies{$Company};
   print(MAIL "\n", 
              $Company->[0], "\n",
              ('~' x (length($Company->[0]) + 1)), "\n");
   foreach $Member ( sort({ uc($a->[0]) cmp uc($b->[0]) } @{$Company->[1]}) )
      { printf(MAIL "   %-34s   %s\n", $Member->[0], $Member->[1]); }
   }
#
# Output the trailing message footer
print(MAIL "\n",
           "Remember to received an updated email list, just send a blank message to\n",
           "email\@charlesworth.com and you should get a reply within 30 seconds.\n\n",
           "For more information or any queries contact sysadmin\@charlesworth.com\n\n");
close(MAIL);


#
#  End of File
#

--Message-Boundary-12668
Content-description: Text from file 'post_all.pl'

#!/usr/bin/perl
#
#
#  "Everyone" EMail Exploder
#
#  Version 2.0
#
#  William F. McCaw  1999
#
#
#  Sends body of message supplied on STDIN to all valid users listed within
#  the computer's /etc/passwd file.
#
#  * Original headers, apart from the sender and subject are discarded.
#  * Recipients are batched with up to 60 per email.
#  * Recipients are specified via 'Bcc:'.
#

#
# Function Prototypes
#
sub SendMessage();


#
# Determine the target company for sending out the email to
#
$TargetCompany = (( defined($ARGV[0]) ) ? $ARGV[0] : '');

#
# Read the message from standard input
#
$MsgSender = '';
$MsgSubject = '';
# Extract the required details from the message's header
while ( defined($Line = <STDIN>) && ($Line =~ /^[^\r\n]/) )
   {
   $Line =~ s/[\r\n]//gs;
   if ( $Line =~ /^Return-Path:\s*<([^>]+)>/i )     # First choice for sender
      { $MsgSender = $1; }
   if ( $Line =~ /^From:\s*(.*)/i && !$MsgSender )  # May be no return path
      { $MsgSender = $1; }
   elsif ( $Line =~ /^Subject:\s*(.+)/i )           # Preserve the subject
      { $MsgSubject = $1; }
   }
# If we are missing certain information then provide some defaults
$MsgSubject = '*** Unknown Subject ***' if ( !$MsgSubject );
# Read in the message body and signature
@MsgBody = <STDIN>;

#
# Read the contents of the system's password file
#
open(PASS, '/etc/passwd') || exit(0);
@Users = <PASS>;
close(PASS);

#
# Send the message to all the users within the password file
#
@MsgRecipients = ();
foreach $User ( @Users )
   {
# Split the current users's details and determine whether to send the
# message to them or not
   ( $EMail, $Password, $UID, $GID, $Name, $Home, $Shell ) = split(/:/, $User);
   next if ( !defined($UID) || ($UID < 1000) || ($UID > 60000) ||
             !defined($Name) || ($Name =~ /^x/) || ($Name eq 'nobody') );
   next if ( $TargetCompany && !($Name =~ /\,\s*$TargetCompany/io) );
# If we have already reached the recipient limit for this message then
# dispatch it and reset the recipient list ready for the next message
   if ( scalar(@MsgRecipients) == 60 )
      {
      SendMessage();
      @MsgRecipients = ();
      }
# Append the current email address to the recipient list
   push(@MsgRecipients, $EMail);
   }
#
# Ensure the folk at the end of the user list receive the message
if ( scalar(@MsgRecipients) )
   { SendMessage(); }



#
#
#  Routine to send the specified message
#
sub SendMessage()
   {
   open(MAIL, "|/usr/bin/exim -t");
   print(MAIL "From: $MsgSender\n") if ( $MsgSender );
   print(MAIL "To: Everyone <discard>\n",
              "Subject: TO EVERYONE: $MsgSubject\n",
              "Bcc: ", join(", ", @MsgRecipients), "\n\n",
              @MsgBody,
              "\n");
   close(MAIL);
   }


#
#  End of File
#
