Why can't I call methods on my Mail::Sender object? - perl

I have this simple part of the program that should send an email to a specified user.
But it has an error that says "Can't call method "MailMsg" on an undefined value"
if ($sender->MailMsg({smtp => 'mail.myISP.com',
from => 'suezy.ourdomainhere.com',
to =>'sample#domainhere.com',
subject => 'this is a test',
msg => "testing....\n?"}) < 0)
{
die "$Mail::Sender::Error\n";
}
print "Successfully sent."
Something wrong? Can anyone give me suggestions please?
Is it possible that I wasn't able to install the package properly?

Your problem is that $sender is not defined - i.e. the variable has no value in it.
Have you created a Sender object doing something like the following:
$sender = new Mail::Sender
{smtp => 'mail.yourdomain.com', from => 'your#address.com'};

Related

How to send pdf from URL using perl and sendmail [Mail::Sendmail]

I have a legacy app that needs to change. it is written in perl and uses send::mail to send mails to users. Previously we sent links in the email message body but now they want pdf attachments instead. The PDF's are generated on another server using php.
the workflow would be
create the email body
get the pdf from another server via a URL
add the pdf as an attachment to the email
send it.
I think I can use
use LWP::Simple;
unless (defined ($content = get $URL)) {
die "could not get $URL\n";
}
to get the contents of the URL but I can't figure out how to use that var as an attachment in sendmail. current sendmail code is:
my %maildata = (To => $to,
From => 'OurSite - Billing <billing#ourSite.com>',
Organization => 'OurSite, LLC http://www.OurSite.com/',
Bcc => 'sent-billing#ourSite.com',
Subject => $subject{$message} || 'ourSite invoice',
Message => $body
);
print STDERR "notify1 now calling sendmail\n";
sendmail(%maildata) || print STDERR $Mail::Sendmail::error;
The other issue I have is I don't know how to find out if the version of sendmail I have (old freebsd system) is even capable of sending attachments ?
ok thanks for the posters who gave me some direction / the will to give it a go.
In the end I built the mime body doing the following
use LWP::Simple;
use MIME::Base64;
unless (defined ($content = get $URL)) {
die "could not get $URL\n";
}
my $pdfencoded = encode_base64($content);
my %maildata = (To => $to,
From => 'OurSite - Billing <billing#ourSite.com>',
Organization => 'OurSite, LLC http://www.OurSite.com/',
Bcc => 'sent-billing#ourSite.com',
Subject => $subject{$message} || 'ourSite invoice',
);
my $boundary = "====" . time() . "====";
$maildata{'content-type'} = "multipart/mixed; boundary=\"$boundary\"";
$maildata{'Message'} = "--".$boundary."\n"."Content-Type: text/plain\n".$body.
"\n--".$boundary."\nContent-Transfer-Encoding: base64\nContent-Type:
application/pdf; name=\"invoice.pdf\"\n".$pdfencoded."\n--".$boundary."--";
sendmail(%maildata) || print STDERR $Mail::Sendmail::error;
This gave me a hand built MIME format for the body content.
Thanks for the help !

Error handling with invalid MAC entry with Perl Net::MAC module

I'm attempting write a Perl script that asks the user to enter a MAC address. I'm using the Net::MAC module to convert whatever format MAC address the user enters to a standard format for me to use later in the script. I've got most of it working but I can't seem to figure out how to handle a situation in which they enter an invalid MAC. Something that couldn't possibly be a MAC address. Such as an entry that includes letters that aren't A-F.
I'm thinking something like the following should work but when it dies it just flat out kills the entire script rather than re-asks the user to enter the MAC again.
use Net::MAC;
my $proceed = "no";
while ($proceed eq "no"){
print "Enter the MAC address: ";
my $mac;
$mac = <>;
chomp($mac);
my $tempMac = Net::MAC->new('mac' => $mac, 'die' => 0);
if ($tempMac->die() eq "0"){
print "Looks like you entered an invalid MAC address. Please try again.\n";
} else {
my $newMac = $tempMac->convert('base' => 16,'bit_group' => 8,'delimeter' => ":");
$proceed = "yes";
}
}
Should this instead use something like a Try, Catch statement? I think in other words, I need to know how to appropriately handle the die() event without having the script completely bail on me.
See https://mvp.kablamo.org/essentials/die-eval for some info on how exceptions work in Perl and how to handle them. Consider Syntax::Keyword::Try for a familiar try/catch paradigm.
use Syntax::Keyword::Try;
my $newMac;
try {
my $tempMac = Net::MAC->new('mac' => $mac);
$newMac = $tempMac->convert('base' => 16,'bit_group' => 8,'delimeter' => ":");
$proceed = "yes";
} catch {
print "Looks like you entered an invalid MAC address. Error: $# Please try again.\n";
}
You can also validate the mac address before passing it to Net::MAC using something like Regexp::Common.
use Regexp::Common 'net';
my $newMac;
if ($mac =~ m/$RE{net}{MAC}/) {
my $tempMac = Net::MAC->new('mac' => $mac);
$newMac = $tempMac->convert('base' => 16,'bit_group' => 8,'delimeter' => ":");
$proceed = "yes";
} else {
print "Looks like you entered an invalid MAC address. Please try again.\n";
}

error when sending email using Dancer2::Plugin::Email;

I am sending email using Dancer2 via the Dancer2::Plugin::Email package. The main code that I have for this is:
sub sendEmail {
my ($params,$email_address,$template) = #_;
my $text = '';
my $tt = Template->new({
INCLUDE_PATH => config->{views},
INTERPOLATE => 1,
OUTPUT => \$text
}) || die "$Template::ERROR\n";
my $out = $tt->process($template,$params);
my $email = email {
from => XXXXX,
to => $email_address,
subject => XXXXX,
body => $text,
'Content-Type' => 'text/html'
};
}
where I have hidden a couple of the fields. I have gotten the following error:
Route exception: open body: Invalid argument at
/usr/local/share/perl/5.22.1/MIME/Entity.pm line 1878. in
/usr/local/share/perl/5.22.1/Dancer2/Core/App.pm l. 1454
It is not occurring all of the time and I haven't been able to find a consistent piece of code that always fails.
I have set the host parameter of the mail server that I am using in the configuration as explained here: https://metacpan.org/pod/Dancer2::Plugin::Email Simple tests show it works, but I get sporadic errors that I can't track down.

Can't call method "verify" on an undefined value

• I am working to migrate a Linux server to a newer one from Ubuntu 10.04 to 12.04
• This server is responsible for executing several a number of Perl modules via crontabs.
• These Perl Modules rely heavily on 30-40 perl extensions.
• I have installed all Perl extensions and the crontabs are able to process successfully except for several Syntax errors caused by the newer versions of these PERL extensions.
• I need some help with modifying the syntax to get the Perl script to process as intended.
This is my error message:
2015/12/28 12:56:48 ./cms.pl 88 FATAL main - Can't call method "verify" on an undefined value at pm/Emails/Core.pm line 438.
Code:
#===================================================================================================
# Send an eamil
# Args: enable_clients?, BCC Arrayref [admin1#a.com, ...], Hashref { email_address, email_subject, email_body }
#===================================================================================================
sub pm::Emails::Core::send_email {
my ($self, $enable_clients, $bcc, $email) = #_;
# die('Invalid BCC array') unless $bcc;
die('Invalid Email hashref') unless ($email && $email->{email_address} && $email->{email_subject} && $email->{email_body});
$email->{email_address} = trim $email->{email_address}; # Trim the email address just to be sure no invalid emails sneak in
my $mime = undef;
my $smtp = undef;
###
# Get a handle to the logger
my $logger = Log::Log4perl->get_logger();
die('Failed to create logger') unless $logger;
###
###
# Send the email using the local SMTP server
# SPAM FILTER NOTES:
# We are sending the email as inlined HTML.
# Sending the email as a multipart with HTML & PlainText is getting flagged as SPAM.
{
my $msg = join(', ',
(
'Time:' . localtime(),
'Sending Email TO: ' . $email->{email_address},
#'BCC: ' . join(',', #$bcc),
'SUBJECT: ' . $email->{email_subject},
'Clients Enabled: ' . ($enable_clients ? 'true' : 'false')
)
);
$logger->warn($msg);
open(FILE, '>>/var/log/mail.log') or die('Failed to open mail log: /var/log/mail.log');
print FILE $msg . "\n";
close FILE;
}
###
if (!defined($self->{_phpversion_})) {
$self->{_phpversion_} = `php -r 'print phpversion();' 2>/dev/null`;
}
###
# Generate the MIME email message
$mime = MIME::Lite->new(
Subject => $email->{email_subject},
To => $email->{email_address},
Type => 'text/html',
Data => $email->{email_body},
'Reply-To' => 'test#test.com',
'Return-Path' => 'test#test.com',
From => 'test#test.com',
Organization => 'Testing',
'X-Mailer' => 'PHP' . $self->{_phpversion_}
);
###
# Check to see if we are sending the email to clients, if not then redirect to another account & update the subject
if ($enable_clients) {
$logger->warn('Sending email to clients is enabled!');
} else {
use Sys::Hostname;
$logger->warn('Sending email to clients is disabled!');
$email->{email_address} = 'test#test.com';
$email->{email_subject} = '<' . hostname . ' - ADMIN ONLY EMAIL> ' . $email->{email_subject};
$mime->replace(Subject => $email->{email_subject});
}
$mime->preamble('');
$mime->top_level(1);
$mime = $mime->as_string();
###
###
# Connect to the SMTP server & send the message
$logger->debug('Connecting to SMPT server');
$smtp = Net::SMTP->new('localhost', Timeout => 60, Debug => 0, Hello => 'test.com');
$logger->debug('Connected to SMPT server');
###
###
# Verify we can send the email to the included addresses
foreach my $email_address (($email->{email_address}), #$bcc) {
$logger->debug('Verifying Email address: ' . $email_address);
next if $smtp->verify($email_address);
$logger->warn('Failed to verify email address: ' . $email_address . ', re-connecting to SMPT');
$smtp = Net::SMTP->new('localhost', Timeout => 60, Debug => 1, Hello => 'test.com');
die('Failed to reconnect to SMPT server') unless $smtp;
last;
}
###
###
# Send the email message
$smtp->mail('test#test.com');
$smtp->bcc(#$bcc, { Notify => ['FAILURE','DELAY', 'SUCCESS'] });
$smtp->to($email->{email_address}, { Notify => ['FAILURE','DELAY', 'SUCCESS'] });
$smtp->data; # This will start the data connection for the message body
$smtp->datasend( $mime ); # This will send the data for the message body
$smtp->dataend; # This will end the message body and send the message to the user
$smtp->quit;
###
use List::Util qw[min];
sleep(min(1, int(rand(2))));
}
Any help on this is greatly appreciated.
You don't create the $smtp object (using $smtp = Net::SMTP->new(...)) until three lines after you try to call the verify() method on it. So of course it's going to be undefined at that point.
The only way that this could ever work is if the $smtp is also created earlier on in code that you haven't shown us. But assuming that you have shown us all mentions of $smtp, then this code can't possibly have worked on the old server only. This is not a problem that is caused by a newer version of Perl, it's a logic error that would never have worked.
The obvious way to fix this is to re-order the code so that the object is created before you try to use it. But as I can only see a small amount of the code, I have no way of knowing whether this would have knock-on effects elsewhere.
Have you considered paying a Perl programmer to help you carry out these migrations? Expecting free consultancy from StackOverflow isn't really a sustainable business model :-/
Update: Ok, so now you've added more code, we can see that the $smtp is initialised a few lines before the call to verify. So why are you getting the error?
If you read the documentation for Net::SMTP, in the section describing the new() method, it says:
On failure undef will be returned and $# will contain the reason for
the failure.
It looks like this is what is happening. But your code isn't checking the return code from the new() and is assuming that it will always work - which is a pretty strange assumption to make. To fine out what is going wrong, you'll need to add some debugging output to the two lines that create your SMTP object. Where you have:
$smtp = Net::SMTP->new(...);
Change it to:
$smtp = Net::SMTP->new(...)
or die $#;
That way, if you fail to connect to the SMTP server, your program will die with a (hopefully) useful error message which will enable you to investigate further.
Incidentally, I don't know where your code comes from, but no-one really recommends Net::SMTP these days. It's all rather low-level. You would be better off looking at Email::Sender or Email::Stuffer (that's the kind of useful knowledge that a Perl programmer would bring to this project..
Hey Guys just Wanted to follow up on this problem. I tried all of your suggestions and was unable to get a solution.
However more in-depth research of the SMTP/Mail running on this machine revealed that it was running Postfix, it turns out this script was written for SendMail. Simply did the following:
Uninstall Postfix-
sudo apt-get purge postfix
Install Sendmail-
sudo apt-get install sendmail
All was resolved, thank you guys for all your help.

Perl Message::Stack example

I am using Perl to try to implement an example for the Message::Stack module from CPAN.
I get the error
Can't locate object method "new" via package "Message::Stack" at stack.pl line 3.
my $stack = Message::Stack->new;
$stack->add(Message::Stack::Message->new(
msgid => 'something_happened',
level => 'error',
scope => 'login_formm',
subject => 'username',
text => 'Something happened!'
));
# Or... for those that want to type less
$stack->add({
msgid => 'something_else_happened',
level => 'error',
scope => 'login_form',
subject => 'password',
text => 'Something else happened!'
});
# ...
my $errors = $stack->for_level('error');
# Or
my $login_form_errors = $stack->for_scope('login_form');
$login_form_errors->for_subject('username');
print "Username has ".$login_form_errors->count." errors.\n";
Please let me know which object I need to load.
I am sure that what the message actually says is
Can't locate object method "new" via package "Message::Stack" (perhaps you forgot to load "Message::Stack"?) at stack.pl line 5.
So, did you forget?
And later, when you actually try to load it using
use Message::Stack
and it tells you
Can't locate Message/Stack.pm in #INC
doesn't it occur to you that it's not found because it isn't there, and needs installing?