Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Trouble emailing zip file

by TonyNY (Beadle)
on Jul 03, 2018 at 13:18 UTC ( #1217814=perlquestion: print w/replies, xml ) Need Help??

TonyNY has asked for the wisdom of the Perl Monks concerning the following question:

Hi

I'm trying to email an attached zip file with the following code but the message just seems to go into cyberspace and not my inbox?

$logfile="$logpath.zip"; $subject="logs for $pkgname"; $user1="user01"; $recipient1="user01@email.org"; if ($userid = $user1){ system("uuencode ${logfile} ${logfile} | mailx -s ${subject} -r ${r +ecipient1}"); #print "$user1\n"; }

I've put the curly braces around the variables to try to avoid interpolation

Also tried without the curly braces but received the same result.

Thanks

Tony

Replies are listed 'Best First'.
Re: Trouble emailing zip file
by haukex (Chancellor) on Jul 03, 2018 at 13:38 UTC
    the message just seems to go into cyberspace and not my inbox?

    Does mailx work when you run it from the command line? If not, then maybe your mail system isn't configured properly? Have you checked your system's logs and checked your mailbox for bounced mails? If mailx does work from the command line, then note that you need to check the return value of system for errors - see its docs, but the bare minimum is system(...)==0 or die "\$?=$?";

    I've put the curly braces around the variables to try to avoid interpolation

    Sorry, that's not how that works, "${foo}" is just another way of writing "$foo". The best way to avoid interpolation is to use the form of system that does not call the shell, where you give system a list of arguments with more than one element. But if you don't go through the shell, you also won't get pipe I/O redirection, which you could solve by a two-step process where the file is first encoded into a temporary file (File::Temp). Or, you could use a module like IPC::Run, which supports I/O redirection. I wrote about this whole topic at length here.

    However, I'd strongly recommend against shelling out in the first place. See Email::Stuffer, here's something adapted from its Synopsis:

    use Email::Stuffer; Email::Stuffer->from('sender@example.com') ->to('user01@email.org')->subject("logs for $pkgname") ->text_body('Here's the log file.') ->attach_file("$logpath.zip") ->send;

      Unfortunately I don't have any of the email modules installed so I will have to try to use the system with the args method

      and the File::Temp module. I've read the links that you have provided and I understand the system with the args but do not

      understand how to use the File::Temp module. Could you please post an example on how to encode the zip file into the temp file?

        Unfortunately I don't have any of the email modules installed

        Please see Yes, even you can use CPAN - if you can install Perl scripts on the server, then normally you can install modules there too, for example with local::lib.

        Could you please post an example on how to encode the zip file into the temp file?

        I initially thought that uuencode could write its output to a file, but I was mistaken, it apparently always writes to its standard output. Since I don't recommend qx//, capturing its output is not trivial - see the section "Use a Piped open" in that link for a way to do it with pure Perl. Alternatively, you don't have to shell out at all, since pack supports uuencoding - with thanks to the Perl Power Tools:

        # takes one argument, the filename to encode # returns one value, the filename of the temporary(!) output file use File::Temp qw/tempfile/; sub uuencode { my ($infile) = @_; my ($tfh,$tfn) = tempfile(UNLINK=>1); open my $fh, '<:raw', $infile or die "$infile: $!"; printf $tfh "begin %03o %s\n", ((stat($infile))[2] & 0666)||0644, $infile; my $buf; print $tfh pack 'u', $buf while read $fh, $buf, 45; print $tfh "`\n", "end\n"; close $fh; close $tfh; return $tfn; }

        That will return the filename of the temporary file that you can then pass to mailx - but make sure to use the "list" form of system, as I showed in the above link as well.

        By the way, in your original post, you said mailx -r $recipient1 - but the -r option sets the From address. Are you sure you've got your mailx command right?

        The Archive::Zip documentation shows how to save a ZIP file to a given filename:

        # Save the Zip file unless ( $zip->writeToFileNamed('someZip.zip') == AZ_OK ) { die 'write error'; }

        The temp filename should be created through File::Temp:

        my ($tempfile, $name) = tempfile(); close $tempfile;

        I was able to get the following to send the zip file but it's corrupted

        Does anyone know why the zip file arrives corrupted but I can open the same zip file when using a shell script?

        use strict; use warnings; use MIME::Base64; use IO::File; my ($subject, $mach, $from, $to, $attachment, $fh, $content); $subject = "Test Mail"; $from = 'user@email.com'; $to = 'user@email.com'; $attachment = "test.zip"; $fh = "mailbody.txt"; open(FILE, '>', $fh) or die "Cannot open $fh: $!"; print FILE "This is a test"; close(FILE); open(MAIL, "|/usr/sbin/sendmail -t"); print MAIL "FROM: $from\n"; print MAIL "TO: $to\n"; print MAIL "Subject: $subject\n"; print MAIL "Content-Type: multipart/mixed; boundary=frontier\n"; print MAIL "--frontier\n"; print MAIL "Content-Type: text/plain; charset=us-ascii\n\n"; open(FILE, '<', $fh) or die "Cannot open $fh: $!"; print MAIL <FILE>; close(FILE); print MAIL "\n\n"; print MAIL "--frontier\n"; chomp(my $basename=`basename $attachment`); print MAIL "Content-Disposition: attachment; filename=$basename\n"; print MAIL "Content-Type: application/octet-stream; name=$attachment\n +\n"; print MAIL "encode_base64( read_file($attachment) )"; open(FILE, '<', $attachment) or die "Cannot open $attachment: $!"; print MAIL <FILE>; print MAIL "\n"; close(FILE); close(MAIL);

      Hi haukex,

      Thanks for your response and yes mailx works from the command line.

Re: Trouble emailing zip file
by hippo (Chancellor) on Jul 03, 2018 at 13:35 UTC
    system("uuencode ${logfile} ${logfile} | mailx -s ${subject} -r ${rec +ipient1}");

    Your $subject contains whitespace. Think about how that's going to affect the mailx command. Why not use a module instead of the shelling-out kludge?

    if ($userid = $user1){

    That's an assignment rather than a test of equality. Also you haven't declared @email so probably the receipient address is wrong too. Time to read the Basic Debugging Checklist maybe?

      Hi hippo

      I guess I need to get into the habit of using chomp to take care of the white spaces.

      Regarding the use of email modules. My work environment is so strict and chances are that we don't have the modules installed.

      What is the command to check if a module is installed?

      Thanks for you help.

        I guess I need to get into the habit of using chomp to take care of the white spaces.

        chomp won't save you here because the whitespace is in the middle of $subject and you probably do actually want to retain the spaces anyway.

        My work environment is so strict and chances are that we don't have the modules installed.

        Which OS? Many of them have packages for perl modules.

        What is the command to check if a module is installed?

        TIMTOWTDI but a simple test to see if (eg.) DBI is installed could be

        perl -MDBI -e 1

        which will just return you to the prompt if it is loaded or throw an error otherwise.

        perldoc -l The::Module

        tells you

        No documentation found for "The::Module"

        ... and

        perl -MThe::Module=99999999 -e1

        tells you

        Can't locate The/Module.pm in @INC (@INC contains: ...)

        ... for misssing modules.

        If the module actually is installed, both will output nothing.

Re: Trouble emailing zip file
by afoken (Canon) on Jul 05, 2018 at 18:33 UTC
    system("uuencode ${logfile} ${logfile} | mailx -s ${subject} -r ${rec +ipient1}");

    Let's hope nobody sets subject to `rm -rf /`. You have created a shell injection vulnerability. Try to avoid using the shell, as others told you. If you absolutely can not avoid the shell, use the multi-argument form. See The problem of "the" default shell for the ugly details.

    And as a bonus, you are not comparing here, but assigning:

    if ($userid = $user1){ system("uuencode ....")

    As long as $user1 contains a true value (i.e. everything but undef, 0 or the empty string), system will be executed, no matter what $userid once contained.

    If you want to compare strings, use eq. For numbers, use ==. (How to remember that.)

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1217814]
Approved by haukex
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others studying the Monastery: (5)
As of 2019-11-17 13:03 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Strict and warnings: which comes first?



    Results (86 votes). Check out past polls.

    Notices?