Solved

How to modify Perl subroutine to add extra parameter

Posted on 2010-09-22
8
462 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 3
8 Comments
 
LVL 26

Accepted Solution

by:
wilcoxon earned 250 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 26

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
Complete VMware vSphere® ESX(i) & Hyper-V Backup

Capture your entire system, including the host, with patented disk imaging integrated with VMware VADP / Microsoft VSS and RCT. RTOs is as low as 15 seconds with Acronis Active Restore™. You can enjoy unlimited P2V/V2V migrations from any source (even from a different hypervisor)

 
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 26

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

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

There are many situations when we need to display the data in sorted order. For example: Student details by name or by rank or by total marks etc. If you are working on data driven based projects then you will use sorting techniques very frequently.…
The Windows functions GetTickCount and timeGetTime retrieve the number of milliseconds since the system was started. However, the value is stored in a DWORD, which means that it wraps around to zero every 49.7 days. This article shows how to solve t…
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…
In a recent question (https://www.experts-exchange.com/questions/29004105/Run-AutoHotkey-script-directly-from-Notepad.html) here at Experts Exchange, a member asked how to run an AutoHotkey script (.AHK) directly from Notepad++ (aka NPP). This video…

724 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