#! perl -w
use Socket;
# BEGIN LOCAL CONFIG PORTION
# Declare the name of the host we're pawning the mail off onto. localhost
# is probably the best option if we've got a mailserver on this
# machine. If not, change it to another host. *YOU MUST HAVE MAIL RELAY
# PERMISSION ON THIS HOST!*
my $mailhost_name = "localhost";  # Fill this in with your local SMTP host name
my $mailhost_ip = ""; # The IP address for the mailhost. If left blank,
                     # we'll go try to figure it out. Should be in
                     # packed format, so no 1.2.3.4 here.
my $mailhost_port = 25; # The port to connect to. Except in the most
                       # bizarre of circumstances, this'll be 25.
my $we_are = ""; # Who we are. Fill this in if your mailserver needs to
                # know. The only way to find this out locally is with
                # POSIX::uname. Not everyone has it, and POSIX is a
                # memory pig anyway. If you don't, we'll try a reverse
                # lookup from the IP address on this end of things after
                # the connection to the mailserver.
#
# END OF LOCAL CONFIG PORTION

# smailer - quicko sub to send mail. Takes from, a reference to an array
# with the to addresses in it, and a reference to an array with
# the actual formatted mail message in it, minus line terminators.
sub smailer ($\@\@){
 my ($from, $to_ref, $message_ref) = @_;


 my $mailhost_paddr; # Where the packed IP address & port will get stuck
 my $they_said;

 # Translate the port to a number if it's a name
 $mailhost_port = getservbyname($mailhost_port, 'tcp')  if $mailhost_port =~ /\D/;
 # Figure the IP address if we need to
 $mailhost_ip ||= inet_aton($mailhost_name);
 # Build the packed socket address
 $mailhost_paddr = sockaddr_in($mailhost_port, $mailhost_ip);

 # Create the socket
 socket(MAILSOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp')) || die "socket:$!";
 # Open the socket
 connect(MAILSOCK, $mailhost_paddr) || die "Connect error: $!";
 # Dup it
 open(MAILOUTSOCK, ">&MAILSOCK") || die "Erro dupping, $! $^E";
 select(MAILSOCK);
 $| = 1;
 select(MAILOUTSOCK);
 $| = 1;
 select(STDOUT);

 # Unless we know who we are, we'd better go figure it out
 my $stuff = getsockname(MAILSOCK) || die "Hey! $^E $!";
 my ($foo, $bar) = unpack_sockaddr_in($stuff);
 $we_are = gethostbyaddr($bar, AF_INET) unless $we_are;

 # Talk to the server. First fetch the initial 'hi there' message
 $they_said = <MAILSOCK>;

 # Say hi
 syswrite(MAILOUTSOCK, "HELO $we_are\cM\cJ", length($we_are) + 7);

 # Wait for them to say hi back
 $they_said = <MAILSOCK>;
 # Make sure we like it
 if (substr($they_said, 0, 1) ne '2') {
   # not a 2 response. Bail
   close(MAILSOCK);
   die "server said $they_said (why?)";
 }

 # Tell it who the mail's from
 syswrite(MAILOUTSOCK, "MAIL FROM: $from\cM\cJ", length($from) + 13);

 # was it OK?
 $they_said = <MAILSOCK>;
 chomp $they_said;
 # Make sure we like it
 if (substr($they_said, 0, 1) ne '2') {
   # not a 2 response. Bail, but not badly
   close(MAILSOCK);
   die "server said $they_said (why?)";
 }

 # Tell 'em who it's going to
 foreach my $recipient (@$to_ref) {
   # Tell it who the mail's from
   syswrite(MAILOUTSOCK, "RCPT TO: $recipient\cM\cJ", length($recipient) + 11);

   # was it OK?
   $they_said = <MAILSOCK>;
   chomp $they_said;
   # Make sure we like it
   if (substr($they_said, 0, 1) ne '2') {
     # not a 2 response. Bail, but not badly
     close(MAILSOCK);
     die "server said $they_said (why?)";
   }
 }

 # Time for the message
 syswrite(MAILOUTSOCK, "DATA\cM\cJ", 6);

 # was it OK?
 $they_said = <MAILSOCK>;
 chomp $they_said;
 # Make sure we like it
 if ((substr($they_said, 0, 1) ne '2')&& (substr($they_said, 0, 1) ne '3')) {
   # not a 2 response. Bail, but not badly
   close(MAILSOCK);
   die "server said $they_said (why?)";
 }

 # Send the message. If a line's got just a period, then send a double
 # period. (SMTP protocol dictates that a message ends with a single
 # period, and we don't want it ending before we're ready)
 foreach my $line (@$message_ref) {
   if ($line eq '.') {
     syswrite(MAILOUTSOCK, "..\cM\cJ", 4);
   } else {
     syswrite(MAILOUTSOCK, "$line\cM\cJ", length($line)+2);
   }
 }

 # 'Kay, send the closing period
 syswrite(MAILOUTSOCK, ".\cM\cj", 3);
 # Did they like the mail?
 $they_said = <MAILSOCK>;
 chomp $they_said;
 # Make sure we like it
 if (substr($they_said, 0, 1) ne '2') {
   # not a 2 response. Bail, but not badly
   close(MAILSOCK);
   die "server said $they_said (why?)";
 }

 # Go away
 syswrite(MAILOUTSOCK, "QUIT\cM\cJ", 6);
 close MAILSOCK;
 close MAILOUTSOCK;
 return 1;
}