#!/usr/bin/perl
#-----------------------------------------------------------------------------
#  This program gives you low level control over an SMTP conversation.
#
#  This program delivers a mail message to an SMTP server.  Command line
#  options tell what server to use and determine the commands this program
#  sends to it.  The program reads the mail message itself from 
#  Standard Input.
#
#  This program does not generate headers inside the mail message (e.g.
#  RFC 822 headers).  You can use the program 'makemail' to do that.
#
#  This program does not extract any envelope information from the mail
#  message or rewrite the message in any way.
#-----------------------------------------------------------------------------

use strict;
use warnings;

use Net::SMTP;
use Getopt::Long;
use Sys::Hostname;
use Data::Dumper;

my $TRUE = 1;
my $FALSE = 0;


sub getSender($) {
    my ($fromOpt) = @_;

    my $retval;
    
    if (defined($fromOpt)) {
        $retval = $fromOpt;
    } else {
        my $user = $ENV{"USER"} || $ENV{"LOGNAME"};
        if (!defined("$user")) {
            die("You didn't supply a sender address with " .
                "--from and I cannot " .
                "default one because neither USER nor LOGNAME environment " .
                "variables is set.");
        } else {
            my $hostname = hostname;
            if (defined($hostname)) {
                $retval = "$user\@$hostname";
            } else {
                $retval = $user;
            }
        }
    }
    return $retval;
}


##############################################################################
#       MAINLINE
##############################################################################

my %options;

$options{"to"} = [];   # Establish as an array reference

GetOptions(\%options, 
           "to=s",
           "from=s",
           "server=s",
           "hello=s",
           "timeout=i",
           "quiet",
           "debug"
           );

if ($options{"debug"}) {
  Net::SMTP->debug(1);
}

if (@{$options{"to"}} == 0) {
    die("Must specify the recipient email address with --to");
} 

my @recipients = @{$options{"to"}};
#print Data::Dumper->Dump([ \@recipients ], [ "recipients" ]);

my $sender = getSender($options{"from"});

my $server = $options{"server"} || "localhost";

my @smtpOptions = ();  # initial value
if (defined($options{"hello"})) {
    push(@smtpOptions, Hello => $options{"hello"});
}
if (defined($options{"timeout"})) {
    push(@smtpOptions, Timeout => $options{"timeout"});
}
if ($options{"debug"}) {
    push(@smtpOptions, Debug => 1);
}

my $smtp = Net::SMTP->new($server, @smtpOptions);

if (!defined($smtp)) {
    die("Failed to connect to SMTP server at '$server'");
}

if (!$options{"quiet"}) {
    print("Server at $server identifies as '" . $smtp->domain . "' " .
          "and says:\n");
    print $smtp->banner;
    print ("\n");
    print ("Reading mail message from Standard Input...\n");
}

my $result = $smtp->mail($sender);
if (!$result) {
    warn("Failed sending MAIL command.  " .
         "Server says '" . $smtp->message . "'");
} else {
    my $rcptError;
    foreach my $recipient (@recipients) {
        my $result = $smtp->recipient($recipient);
        if (!$result) {
            warn("Failed sending RCPT command for '$recipient'.  " .
                 "Server says '" . $smtp->message . "'");
            $rcptError = $TRUE;
        }
    }
    if ($rcptError) {
        $smtp->quit;
        die("send error");
    } else {
        my @message = <STDIN>;

        my $result = $smtp->data(@message);

        if (!$result) {
            warn("Server rejected message.  " .
                 "Server says '" . $smtp->message . "'");
            $smtp->quit;
            die("rejected");
        } else {
            $smtp->quit;
            if (!$options{"quiet"}) {
                my $recipientDesc;
                if (@recipients == 1) {
                    $recipientDesc = $recipients[0];
                } else {
                    $recipientDesc = scalar(@recipients) . " recipients";
                }
                print("Message sent to $recipientDesc from $sender.\n");
            }
        }
    }
}
