Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

How to modify Perl subroutine to add extra parameter

Posted on 2010-09-22
8
Medium Priority
?
469 Views
Last Modified: 2013-12-25
Hi,

I've been trying to modify a simple SMTP mail send script that I found online, but am struggling, being a Perl newbie and all. The script is as follows:
 
sub send_mail # send SMTP mail
	{
        my ($from, $to_addr, $subject, $body, $msg);

        $from       = shift;
        $to_addr    = shift;
        $subject	= shift;
        $body       = shift;
		$date 		= strftime "%a, %d %b %y %H:%M:%S %z",localtime;
        
        $msg = "MIME-Version: 1.0\n"
             . "From: $from\n"
             . "To: " . ( ref($to_addr) ? join(';', @$to_addr) : $to_addr ) . "\n"
             . "Date: $date\n"
             . "Subject: $subject\n\n"      # Double \n
             . $body;
		
        #
        # Open an SMTP session
        #
        $smtp = Net::SMTP->new( $SMTP_HOST,
                                'Debug' => 0,       # Change to a 1 to turn on debug messages
                            );

        if(!defined($smtp) || !($smtp))
        {
            print "SMTP ERROR: Unable to open smtp session.\n";

            return 0;
        }

        #
        # Pass the 'from' email address, exit if error
        #
        if (! ($smtp->mail( $from ) ) )
        {
            return 0;
        }

        #
        # Pass the recipient address(es)
        #
        if (! ($smtp->recipient( ( ref($to_addr) ? @$to_addr : $to_addr ) ) ) )
        {
            return 0;
        }

        #
        # Send the message
        #
        $smtp->data( $msg );

        $smtp->quit;
    }

Open in new window


I would like to pass the subroutine an extra parameter "bcc" which it would then use, if passed, to bcc the email. At the moment I can't work out how to do it.

Also I don't understand how comes the script can handle multiple "to" addresses, which it apparently can - how does it know which parameter is an email address and which is one of the parameters passed after the email addys? I get the impression its this line : ( ref($to_addr) ? join(';', @$to_addr) : $to_addr )  -- but no idea how it works!

Thanks
0
Comment
Question by:georgemason
  • 4
  • 3
8 Comments
 
LVL 27

Accepted Solution

by:
wilcoxon earned 1000 total points
ID: 33735704
Here's a slightly reformatted and modified version of your sub that will accept bcc addresses as the third argument (after to addresses).  Just change the order of arguments on the "my (...) = @_" line if you want it to be in a different order.

For to (and bcc), if you want to pass multiple addresses, they need to be in an array ref.  You are correct that it is the line with the ref($to_addr) that handles multiple vs single.  Here's a few examples to help illustrate it.

send_mail('me@here.net', 'you@there.net', undef, 'single recipient, no bcc', $body, $msg);
send_mail('me@here.net', ['you@there.net', 'him@elsewhere.net'], 'me@here.net', 'multiple to and single bcc', $body, $msg);
# send SMTP mail
sub send_mail {
    my ($from, $to_addr, $bcc, $subject, $body, $msg) = @_;

    $date = strftime "%a, %d %b %y %H:%M:%S %z",localtime;
    
    $msg = "MIME-Version: 1.0\n"
         . "From: $from\n"
         . "To: " . ( ref($to_addr) ? join(';', @$to_addr) : $to_addr ) . "\n"
         . "Date: $date\n"
         . "Subject: $subject\n\n"      # Double \n
         . $body;
            
    #
    # Open an SMTP session
    #
    $smtp = Net::SMTP->new( $SMTP_HOST,
                            Debug => 0, # Change to 1 to turn on debug messages
                        );

    unless ($smtp) {
        print "SMTP ERROR: Unable to open smtp session.\n";
        return 0;
    }

    #
    # Pass the 'from' email address, exit if error
    #
    $smtp->mail($from) or return 0;

    #
    # Pass the recipient address(es)
    #
    $smtp->recipient( ( ref($to_addr) ? @$to_addr : $to_addr ) ) or return 0;
    $smtp->bcc( ( ref($bcc) ? @$bcc : $bcc ) ) or return 0;

    #
    # Send the message
    #
    $smtp->data( $msg );

    $smtp->quit;
}

Open in new window

0
 
LVL 7

Expert Comment

by:ziceva
ID: 33735767
Try this:

[code]
sub send_mail # send SMTP mail
      {
        my ($from, $to_addr,$bcc, $subject, $body, $msg);

        $from       = shift;
        $to_addr    = shift;
        $bcc        = shift;
        $subject      = shift;
        $body       = shift;
      $date             = strftime "%a, %d %b %y %H:%M:%S %z",localtime;
       
        $msg = "MIME-Version: 1.0\n"
             . "From: $from\n"
             . "To: " . ( ref($to_addr) ? join(';', @$to_addr) : $to_addr ) . "\n"
             . "Bcc: $bcc\n"
             . "Date: $date\n"
             . "Subject: $subject\n\n"      # Double \n
             . $body;
            
        #
        # Open an SMTP session
        #
        $smtp = Net::SMTP->new( $SMTP_HOST,
                                'Debug' => 0,       # Change to a 1 to turn on debug messages
                            );

        if(!defined($smtp) || !($smtp))
        {
            print "SMTP ERROR: Unable to open smtp session.\n";

            return 0;
        }

        #
        # Pass the 'from' email address, exit if error
        #
        if (! ($smtp->mail( $from ) ) )
        {
            return 0;
        }

        #
        # Pass the recipient address(es)
        #
        if (! ($smtp->recipient( ( ref($to_addr) ? @$to_addr : $to_addr ) ) ) )
        {
            return 0;
        }

        #
        # Send the message
        #
        $smtp->data( $msg );

        $smtp->quit;
    }

[/code]

The "To" param can be an array like this:
@mail_list=("user1@domain1.com","user2@domain2.com");
0
 
LVL 27

Expert Comment

by:wilcoxon
ID: 33735840
ziceva's solution has three problems:
1) It will probably (not 100% sure) print the bcc recipient in the message (the $msg is the data/body)
2) It will not actually send the email to the bcc recipient ($smtp->recipient or $smtp->bcc must be called)
3) His description of the "To" param is inaccurate - it has to be an arrey reference (not an array)
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 1

Author Comment

by:georgemason
ID: 33736183
@wilcoxon - excellent post in the first place, and thanks for the critique of the other poster's code. I've implemented your suggestions and the script works flawlessly.

One more question I have, since you're so good at explanations!

I notice you're using "unless (condition) command" to only run commands in the event that the condition evaluates to something other than zero - I assume this would occur if there was an error. Is there any way that I can use the same idea, to only run commands if something completes without error?

What I'm thinking is that I'm making some system calls to reset passwords etc. as below:

system("echo $password | passwd --stdin $reseller");
            print LOGFILE &currentTime . " Created user $reseller with password $password\n";

I'd like the log entry to only occur if the passwd command exits correctly - i'm guessing this can be done with unless?
0
 
LVL 27

Expert Comment

by:wilcoxon
ID: 33736401
Sure.  In the case of system, it would need to be something like these...

# simplest that works because system returns 0 on success
system("echo $password | passwd --stdin $reseller") or
print LOGFILE &currentTime . " Created user $reseller with password $password\n";

# alternate that is a little more readable - only does print on successful system call
my $stat = system("echo $password | passwd --stdin $reseller");
print LOGFILE &currentTime . " Created user $reseller with password $password\n" unless $stat;

On a system or exec call failure, you can examine $? to figure out exactly what the problem is (see "perldoc -f system" for more details).
0
 
LVL 1

Author Comment

by:georgemason
ID: 33736889
Great explanation, for your extra help I'll double the points. Thanks for taking the time to post - really appreciated.
0
 
LVL 1

Author Comment

by:georgemason
ID: 33736920
Apologies, awarded points to wrong person, have requested it be changed.

DOH!
0
 
LVL 1

Author Closing Comment

by:georgemason
ID: 33760774
Excellent response, worked perfectly and I learnt a bit in the process. Thanks very much!
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Checking the Alert Log in AWS RDS Oracle can be a pain through their user interface.  I made a script to download the Alert Log, look for errors, and email me the trace files.  In this article I'll describe what I did and share my script.
In the first part of this tutorial we will cover the prerequisites for installing SQL Server vNext on Linux.
The viewer will learn how to look for a specific file type in a local or remote server directory using PHP.
In this fifth video of the Xpdf series, we discuss and demonstrate the PDFdetach utility, which is able to list and, more importantly, extract attachments that are embedded in PDF files. It does this via a command line interface, making it suitable …
Suggested Courses

885 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question