Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Re: Sending Multi file types as e-mail attachments

by Athanasius (Archbishop)
on Nov 16, 2015 at 03:36 UTC ( [id://1147771]=note: print w/replies, xml ) Need Help??


in reply to Sending Multi file types as e-mail attachments

Hello merrymonk,

I also added the $content_type ‘definition ’ for ms-word and used the ms-excel definition for both .xls and .xlsx files (which did seem to work).

I suspect that the code “worked” for the .xlsx file rather by accident than by design. The problem is that the value of $content_type is set correctly only when one of the regex matches succeeds. In the case of files ending in .xlsx and .docx, there is no possible regex match, so $content_type retains whatever value it had in the previous loop iteration. Since the file testx.xlsx happens to follow the file testaaa.xls, $content_type still has the value 'application/vnd.ms-excel'. But when it comes to the file wordtest.docx, the regex tests again all fail and so $content_type still has the value 'application/vnd.ms-excel', which produces a garbled attachment.

There are two deficiencies in the code which here combine to produce the problem. First, lexical variables should be declared at the point of first use, to limit their scope as much as possible. By declaring $content_type outside the inner loop, you allow it to retain a spurious value from one iteration to the next. Second, a series of matches should always be terminated by a “no match” clause, handling the case where a match failed to occur. This is good practice even when (as here) it seems as though one of the matches is bound to succeed.

So, here is a suggested improvement (untested):

... for my $ja (0 .. $ja_max - 1) { my $attachBinaryFile = $attach_list[$ja]; my $content_type; if ($attachBinaryFile =~ /\.gif$/i) { $content_type = 'image/g +if' } elsif ($attachBinaryFile =~ /\.jpg$/i) { $content_type = 'image/j +peg' } elsif ($attachBinaryFile =~ /\.zip$/i) { $content_type = 'applica +tion/zip' } elsif ($attachBinaryFile =~ /\.html$/i) { $content_type = 'text/ht +ml' } elsif ($attachBinaryFile =~ /\.pdf$/i) { $content_type = 'applica +tion/pdf' } elsif ($attachBinaryFile =~ /\.xls$/i) { $content_type = 'applica +tion/vnd.ms-excel' } elsif ($attachBinaryFile =~ /\.doc$/i) { $content_type = 'applica +tion/vnd.ms-word' } elsif ($attachBinaryFile =~ /\.log$/i) { $content_type = 'applica +tion/octet-stream' } else { warn "Unrecognized file +type: $attachBinaryFile"; next; } $smtp->datasend("--$boundary\n"); ...

...and then you will need to add code for the cases where the file extension is .xlsx or .docx.

(Actually, a better implementation of the above would be to use a hash to associate file extensions with their corresponding content types.)

Hope that helps,

Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Replies are listed 'Best First'.
Re^2: Sending Multi file types as e-mail attachments
by merrymonk (Hermit) on Nov 16, 2015 at 08:33 UTC
    Thank you - I appreciate your suggestions. Below is modified version where I have implemented using a hash for the content_type. This fails when the content type is not 'known'.
    Does anyone know where I can find what the content type description should be for:
    1. in general - any file type;
    2. specifically - for ms word and excel having extensions .docx and .xlsx respectively?
    use strict; use warnings; use Net::SMTP; use MIME::Base64 qw( encode_base64 ); my ($host_em, $to_em, $cc_em, $from_em, $password_em, @to_email_list, +$jt, $jt_max, $smtp, $attachBinaryFile, @attach_list, $ja, $ja_max, $ +buf); my ($content_type, $plength, $command_ok, $auth_ok, %file_content, $fi +le_split_tot, @file_split); # set the file contant definition $file_content{gif} ='image/gif'; $file_content{jpg} ='image/jpeg'; $file_content{zip} ='application/zip'; $file_content{html} ='text/html'; $file_content{pdf} ='application/pdf'; $file_content{xls} ='application/vnd.ms-excel'; $file_content{doc} ='application/vnd.ms-word'; $file_content{log} ='application/octet-stream'; # host name required $host_em = 'mail.xxxx'; # valid e-mail address from which e-mail is to be sent and password fo +r this e-mail address required $from_em = 'xxx@xxx'; $password_em = 'xxxx'; # valid e-mail address to which e-mail is to be sent $to_email_list[0] = 'yyy@yyy'; # list of attachments for the e-mail $attach_list[0] = 'Bach.jpg'; $attach_list[1] = 'workshop notes.pdf'; $attach_list[2] = 'Booking form.pdf'; $attach_list[3] = 'testaaa.xls'; $attach_list[4] = 'testx.xlsx'; $attach_list[5] = 'wordtest.docx'; $ja_max = scalar(@attach_list); my $boundary = 'frontier'; $jt_max = scalar(@to_email_list); for($jt = 0; $jt < $jt_max; $jt ++) { $to_em = $to_email_list[$jt]; $smtp = Net::SMTP->new($host_em, SSL => 1); # test that auth is OK $auth_ok = $smtp->auth($from_em, $password_em); print "jt <$jt> command_ok <$auth_ok>\n"; $smtp->mail($from_em); $smtp->to($to_em); $smtp->data; $smtp->datasend("From: " . $from_em); $smtp->datasend("\n"); $smtp->datasend("To: " . $to_em); $smtp->datasend("\n"); $smtp->datasend('Subject: Test of e-mail list'); $smtp->datasend("\n"); $smtp->datasend("Content-type: multipart/mixed;\n\tboundary=\"$bou +ndary\"\n"); $smtp->datasend("\n"); for($ja = 0; $ja < $ja_max; $ja ++) { $attachBinaryFile = $attach_list[$ja]; # find file type @file_split = split(/\./, $attachBinaryFile); $file_split_tot = scalar(@file_split); if(exists($file_content{$file_split[$file_split_tot - 1]})) { $content_type = $file_content{$file_split[$file_split_tot +- 1]}; print "ext <$file_split[$file_split_tot - 1] content_type +<$content_type>\n"; $smtp->datasend("--$boundary\n"); $smtp->datasend("Content-Type: $content_type; name=\"$atta +chBinaryFile\"\n"); $smtp->datasend("Content-Transfer-Encoding: base64\n"); $smtp->datasend("Content-Disposition: attachment; filename +=\"$attachBinaryFile\"\n"); $smtp->datasend("\n"); print "$ja <$ja> attachment <$attachBinaryFile> type <$con +tent_type>\n"; $buf = '';; open(DAT, "$attachBinaryFile") || die("Could not open bina +ry file!"); binmode(DAT); local $/=undef; while (read(DAT, my $picture, 4096)) { $buf = &encode_base64( $picture ); $smtp->datasend($buf); } $smtp->datasend("--$boundary\n"); close(DAT); $smtp->datasend("\n"); $smtp->datasend("--$boundary\n"); } else { print "no valid content for $file_split[$file_split_tot - +1] is available\n"; } # test that e-mail has been sent ok $command_ok = $smtp->dataend(); print "jt <$jt> command_ok <$command_ok>\n"; $smtp->quit; } } print "\n\n\nFinished\n";
      There was an error with the position of one of the } at the end of the Perl that I sent in my reply above.
      Below is the complete Perl again since I thought it would be simpler this way.
      use strict; use warnings; use Net::SMTP; use MIME::Base64 qw( encode_base64 ); my ($host_em, $to_em, $cc_em, $from_em, $password_em, @to_email_list, +$jt, $jt_max, $smtp, $attachBinaryFile, @attach_list, $ja, $ja_max, $ +buf); my ($content_type, $plength, $command_ok, $auth_ok, %file_content, $fi +le_split_tot, @file_split); # set the file contant definition $file_content{gif} ='image/gif'; $file_content{jpg} ='image/jpeg'; $file_content{zip} ='application/zip'; $file_content{html} ='text/html'; $file_content{pdf} ='application/pdf'; $file_content{xls} ='application/vnd.ms-excel'; $file_content{doc} ='application/vnd.ms-word'; $file_content{log} ='application/octet-stream'; # host name required $host_em = 'mail.xxxx'; # valid e-mail address from which e-mail is to be sent and password fo +r this e-mail address required $from_em = 'xxx@xxx'; $password_em = 'xxxx'; # valid e-mail address to which e-mail is to be sent $to_email_list[0] = 'yyy@yyy'; # list of attachments for the e-mail $attach_list[0] = 'Bach.jpg'; $attach_list[1] = 'workshop notes.pdf'; $attach_list[2] = 'Booking form.pdf'; $attach_list[3] = 'testaaa.xls'; $attach_list[4] = 'testx.xlsx'; $attach_list[5] = 'wordtest.docx'; $ja_max = scalar(@attach_list); my $boundary = 'frontier'; $jt_max = scalar(@to_email_list); for($jt = 0; $jt < $jt_max; $jt ++) { $to_em = $to_email_list[$jt]; $smtp = Net::SMTP->new($host_em, SSL => 1); # test that auth is OK $auth_ok = $smtp->auth($from_em, $password_em); print "jt <$jt> command_ok <$auth_ok>\n"; $smtp->mail($from_em); $smtp->to($to_em); $smtp->data; $smtp->datasend("From: " . $from_em); $smtp->datasend("\n"); $smtp->datasend("To: " . $to_em); $smtp->datasend("\n"); $smtp->datasend('Subject: Test of e-mail list'); $smtp->datasend("\n"); $smtp->datasend("Content-type: multipart/mixed;\n\tboundary=\"$bou +ndary\"\n"); $smtp->datasend("\n"); for($ja = 0; $ja < $ja_max; $ja ++) { $attachBinaryFile = $attach_list[$ja]; # find file type @file_split = split(/\./, $attachBinaryFile); $file_split_tot = scalar(@file_split); if(exists($file_content{$file_split[$file_split_tot - 1]})) { $content_type = $file_content{$file_split[$file_split_tot +- 1]}; print "\n$ja <$ja> attachment <$attachBinaryFile> ext <$fi +le_split[$file_split_tot - 1] content_type <$content_type>\n"; $smtp->datasend("--$boundary\n"); $smtp->datasend("Content-Type: $content_type; name=\"$atta +chBinaryFile\"\n"); $smtp->datasend("Content-Transfer-Encoding: base64\n"); $smtp->datasend("Content-Disposition: attachment; filename +=\"$attachBinaryFile\"\n"); $smtp->datasend("\n"); $buf = '';; open(DAT, "$attachBinaryFile") || die("Could not open bina +ry file!"); binmode(DAT); local $/=undef; while (read(DAT, my $picture, 4096)) { $buf = &encode_base64( $picture ); $smtp->datasend($buf); } $smtp->datasend("--$boundary\n"); close(DAT); $smtp->datasend("\n"); $smtp->datasend("--$boundary\n"); } else { print "no valid content for $file_split[$file_split_tot - +1] is available\n"; } } # test that e-mail has been sent ok $command_ok = $smtp->dataend(); print "jt <$jt> command_ok <$command_ok>\n"; $smtp->quit; } print "\n\n\nFinished\n";
        I have found an answer to my last question.
        The site http://help.dottoro.com/lapuadlp.php
        amongst others has a list.
        .. but I am still looking for how to add the options

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1147771]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others musing on the Monastery: (5)
As of 2024-03-29 22:26 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found