Email::Sender how to attach file in Perl? - perl

System: Perl 5.26.1 on Ubuntu 18.04 LTS. There is a subroutine that does email in a file called util2.pl. The subroutine is called mailadming() and has a bunch of parameters like the SMTP server info, to and from addresses, etc. util2.pl is required into the main program.
I've been searching for about 2 hours on various sites and Google, and reading the manual on Email::Sender and I cannot seem to find how to attach a file when using Email::Sender. I am upgrading a machine and was using Mail::Sender but Mail::Sender is deprecated for Email::Sender, and docs are sparse on Email::Sender.
I could not find any info at all on file attachments in Email::Sender docs.
Since Mail::Sender is not updated anymore it would be a bad idea to continue using that. We have a lot invested in Perl so we just can't change tools at this point.
Can anyone help me out please?
Should I use another email module for Perl? Email::Sender seems to be updated the most often and most recent.
EDIT: This is the code I have so far:
my $email = Email::Stuffer->new(
text_body=>$body,
subject=>$subjparam,
from=>$from, # or use ->from($email1, $email2...)
transport=>Email::Sender::Transport::SMTP->new({
host => $smtpserver,
port => $smtpport,
username => $smtpuser,
password => $smtppw,
}),
);
The error I get right now is:
Can't use string ("text_body") as a HASH ref while "strict refs" in use at /usr/local/share/perl/5.26.1/Email/Stuffer.pm line 224.
I can't just create the email and send it in one shot, I have to create the email, look for other options to add to it (like CC addresses and if I need to attach a file), etc. And code I got from Perl Maven just doesn't work.

There are two components to the process, constructing the email and sending it. Email::Sender only handles the latter, and it shows how to use Email::Simple to construct simple emails. To construct more advanced emails like those with attachments, you want the more powerful Email::MIME, and there is a wrapper of Email::MIME and Email::Sender together called Email::Stuffer, which provides easy APIs for attaching files.
use strict;
use warnings;
use Email::Stuffer;
my $mail = Email::Stuffer->to($to)->from($from)->subject($subj)->text_body($text);
$mail->attach_file('/path/to/file.txt'); # guesses MIME type
# or if you have the file data in memory
$mail->attach($contents, name => 'foo.dat', filename => 'foo.dat',
content_type => 'application/octet-stream');
# to change the transport
$mail->transport('SMTP', host => ...);
$mail->transport(Email::Sender::Transport::SMTP->new(...));
$mail->send_or_die;

Related

How to scrape a ASP website using perl?

Please tell me which module is used to scrape a website which is completely developed in ASP and all it's contents are not in proper HTML syntax.
It does not matter which language was used to develop the website. All that you (client) get from the website is the produced HTML (or broken HTML in this case).
You can use the "LWP" library and the "get" function to read the website content into a variable... and then analyze it using regular expressions.
Like this:
use strict;
use LWP::Simple;
my $url = 'http://...';
my $content = get $url;
if ($content =~ m/.../) {
...
}
Or you could use WWW::Mechanize. It builds upon LWP (which LWP::Simple is a very simple subset of) and provides lots of handy 'browser-like' behavior. For example, the typical session management of ASP-generated websites with login cookies and stuff gets handled by Mechanize automatically.
use strict; use warnings;
use WWW::Mechanize;
my $mech = WWW::Mechanize->new;
$mech->get( 'http:://www.example.org/login.asp' );
$mech->submit_form(
form_number => 3,
fields => {
username => 'test',
password => 'secret',
}
);
While this first of all is good for testing, it still has LWPs inherited methods and you can access the plain request. You can thus access the request as well, while still having the power of the built-in parser to access forms and links.
Also consider using a proper HTML parser, even if the website's output is no very fancy. There are several of these around that can handle it. It will be a lot easier than just building up a bunch of regexes. These will get hard to maintain once you need to go back because the page has changed something.
Here's a list of related questions that have info on this subject:
Parse html using Perl
Parse html using Perl
Perl parse links from HTML Table
What are some good ways to parse HTML and CSS in Perl?

How to send mail with attachments in Plone using a template approach?

I've been reading the official docs about sending emails from Plone using some templates, and it's working so far.
My question is: how do I add attachments using the template approach?
The MailHost.send command takes both python (unicode) strings and email.Message objects. That means you can use the python email package to construct a proper MIME message with attachments.
The standard library includes a great page of examples; any text can still be generated by templates just like in the documentation you linked.
Use Python's email module.
Examples:
http://docs.python.org/library/email-examples.html
The composed messages can be passed to context.MailHost (the MTA of Zope).
It is in every case better generating and sending out emails from the Python level instead of using the old DTML sendmail facade...don't use it.
This is my solution, maybe it is not the best:
create a mime_file DTML Method in portal_skin/custom:
<dtml-mime type="text/text; charset=utf-8" encode="7bit">
<dtml-var "text">
<dtml-boundary type="application/octet-stream" disposition="attachment"
filename_expr="nomefile"><dtml-var "file"></dtml-mime>
Call it (for example from a Python Script) as:
message = context.mime_file(file=a_file, text=message, nomefile='attach_name.pdf')
context.MailHost.send(message, mTo, mFrom, mSubj)
where a_file is the content of the file.
inspired by:
http://www.zope.org/Members/visibleoffice/HowTo.2003-10-22.1455
This is a quick&dirt solution, using Python Scripts.

Perl CGI problem

I'm doing some development work that uses an embedded Linux for the OS and Boa for the web server. I have a web page that posts to a CGI script, handles the form data, and replies. My development environment was Ubuntu and everything worked fine, but when I ported my code over to the embedded Linux, the CGI module did not instantiate (or at least does not seem to instantiate). Here is a stripped down section of my code. The print statement complains about an uninitialized variable.
use CGI;
use strict;
use warnings;
my $cgiObj = CGI->new();
print $cgiObj->param('wlanPort');
Again, this works fine in my development environment, but fails in the embedded environment. The CGI.pm is installed and there are no errors generated on the CGI->new() command. I have also verified that the form data is being sent, but obviously can't guarantee that it is being received by the Perl script.
I have a feeling that it is a Boa configuration issue and that's what I'll be looking into next. I'm fairly new to Perl, so I'm not sure what else to do. Any ideas?
EDIT: Definitely not a Boa config issue. Still looking into it.
UPDATE:
I've simplified my code to the following:
#!/usr/bin/perl
use CGI qw(:standard);
$data = param('wlanPort') || '<i>(No Input)</i>';
print header;
print <<END;
<title>Echoing user input</title>
<p>wlanPort: $data</p>
END
As expected, it prints (No Input)
I should also point out that the form is enctype="multipart/form-data" because I have to have a file upload capability and I am using the "POST" method.
I used the HttpFox plugin to inspect the post data and checked on the wlanPort value:
-----------------------------132407047814270795471206851178 Content-Disposition: form-data;
name="wlanPort"
eth1
So it is almost definitely being sent...
UPDATE 2: I installed the same version of Perl and Boa being used in the embedded system on my Ubuntu laptop. Works on the laptop, not in the device, which is the same result. I've told my employer that that I've exhausted all possibilities other than the way Boa and (Micro) Perl are built on the device vs. in Ubuntu.
CGI is a beautifully simple protocol and while I cannot answer your question directly, I can suggest some techniques to help isolate the problem.
If your form is being submitted via POST, then the contents of that form will appear as a URLencoded string in the content of the HTTP request your script is getting. Without using the CGI module at all, you should be able to read the the request from STDIN:
my $request = "";
while (<STDIN>) {
$request .= $_;
}
if (open my $out, ">>/tmp/myapp.log") {
print $out $request;
close $out;
}
You can then examine /tmp/myapp.log to see if you are getting all the information from the request that you think you are.
For completeness, if your form submits via GET, then the arguments will be in the environment variable QUERY_STRING, which you can look at in Perl with $ENV{'QUERY_STRING'}.
There should be no difference in the way CGI's object interface and functional interface parses the request. I am not familiar with boa, but I can't imagine it breaking basic CGI protocol.
A common problem is that you named the form parameter one thing and are looking for a different parameter name in the CGI script. That's always a laugh.
Good luck and hope this helps some.
I know this is very old post and OP may not be interested in any new info related to this, but the general question about how to debug CGI scripts has some relevance still. I had similar issues with dev vs. prod environments. To help those who stumble upon this thread, I am posting my experience in dealing with this situation. My simple answer is, to use Log::Log4perl and Data::Dumper modules to demystify this (assuming there is a way to access logs on your prod environment). This way with negligible overhead, you can turn on tracing when problems creep in (even if the code worked before, but due to changes over time, it started failing). Log every relevant bit of information at appropriate log level (trace, debug, info, warning, error, fatal) and configure what level is good for operations. Without these mechanisms, it will be very difficult to get insight into production operations. Hope this helps.
use CGI;
use Log::Log4perl qw(easy);
use Data::Dumper;
use strict;
use warnings;
my $cgiObj = CGI->new();
my $log = Log::Log4perl::get_logger();
$log->trace("CGI Data: " . Dumper($cgiObj));
print $cgiObj->param('wlanPort');

Sending Mail Through Perl

I am using the below code to send an email
#!/usr/bin/perl
sub BEGIN {
unshift (#INC,'/opt/dev/common/mds/perlLib');
}
use Mail::Sender;
$sender = new Mail::Sender
{smtp => 'xxx.xxx.x.xx', from => 'abc#xyz.xom'};
$sender->MailFile({to => 'abc#xyz.xom',
subject => 'Here is the file',
msg => "I'm sending you the list you wanted."});
$sender->Close;
But, it is not sending the mail at all. What is wrong in my code?
I don't use that module because MIME::Entity works so much better, but from working with mail, I can tell you that you are getting ahead of yourself, and making assumptions rather than deductions.
perldoc on that module shows several methods -- and MailFile is for attaching and sending files. If it fails when sending a message without an attached file, I'd have to say I'm not surprised. Has that worked anywhere else?
Were you able to make MailMsg() work? If you cannot, (the syntax is very similar but with fewer things to go wrong), then you may have a problem with connecting to server. From the xxx.xxx.xxx.xxx bit, I'd have to assume you're using an ip address. Try a hostname. Also, set on_errors to die() or maybe warn(), and see if you can trap the error. Most mail attempts fail during the connect to the server/creation of the object -- then the sending attempt will by definition fail, but often without telling you why.
If you cannot connect, make sure that you aren't needing to authenticate to your server.

What's a good Perl OO interface for creating and sending email?

I'm looking for a simple (OO?) approach to email creation and sending.
Something like
$e = Email->new(to => "test <test#test.com>", from => "from <from#from.com>");
$e->plain_text($plain_version);
$e->html($html_version);
$e->attach_file($some_file_object);
I've found Email::MIME::CreateHTML, which looks great in almost every way, except that it does not seem to support file attachments.
Also, I'm considering writing these emails to a database and having a cronjob send them at a later date. This means that I would need a $e->as_text() sub to return the entire email, including attachments, as raw text which I could stuff into the db. And so I would then need a way of sending the raw emails - what would be a good way of achieving this?
Many thanks
You have to read the documentation more carefully, then two of your three questions would be moot.
From the synopsis of Email::MIME::CreateHTML:
my $email = Email::MIME->create_html(
You obviously get an Email::MIME object. See methods parts_set and parts_set for so called attachments.
Email::MIME is a subclass of Email::Simple. See method as_string for serialising the object to text.
See Email::Sender for sending mail.
You might check out perl MIME::Lite.
You can get the message as a string to save into a database:
### Get entire message as a string:
$str = $msg->as_string;
Email::Stuff is a nice wrapper for Email::MIME. You don't need to care about the MIME structure of the mail, the module does it for you.
Email::Stuff->from ('cpan#ali.as' )
->to ('santa#northpole.org' )
->bcc ('bunbun#sluggy.com' )
->text_body($body )
->attach (io('dead_bunbun_faked.gif')->all,
filename => 'dead_bunbun_proof.gif')
->send;
It also has as_string.