Link to home
Start Free TrialLog in
Avatar of nigg
niggFlag for Israel

asked on

Attachment in Form / Sendmail Script

do you know about attachments like: <input type=file name=attach0> so that it gets attached to the mail?


<Form action><input type=text name=recipient size=60><input type=text name=cc size=60><input type=text name=bcc size=60><input type=text name=subject size=60></input type=file name=attach0> </Form>

Script:
#!/usr/bin/perl
# Get the input
read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
$mailprog ="/usr/sbin/sendmail";
# Split the name-value pairs
@pairs = split(/&/, $buffer);

foreach $pair (@pairs)
{
    ($name, $value) = split(/=/, $pair);

    # Un-Webify plus signs and %-encoding
    $value =~ tr/+/ /;
    $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

    # Stop people from using subshells to execute commands
    # Not a big deal when using sendmail, but very important
    # when using UCB mail (aka mailx).
      $value =~ s/~!/ ~!/g;

    # Uncomment for debugging purposes
    # print "Setting $name to $value<P>";

    $FORM{$name} = $value;
    if ($value =~ /\<\!--\#(.*)\s+(.*)\s?=\s?(.*)--\>/) { &kill_input; }
    if ($value =~ /[;><\*`\|]/) { &kill_input; }    
}
print "Content-type: text/html\n\n";

if ($FORM{'send'} eq "yes") {
  &no_data unless $FORM{'recipient'};
  &no_data unless $FORM{'from'};
  &no_data unless $FORM{'subject'};
  &Output;
  ##  Set up the Email Delivery Agent.
  $mailprog ="/usr/lib/sendmail";
  open(MAIL, "| $mailprog -t ") || die $!;
  print MAIL "To: $FORM{'recipient'}\n";
  print MAIL "From: $FORM{'from'}\@eshal.com\n";
  print MAIL "Subject: $FORM{'subject'}\n";
  print MAIL "CC: $FORM{'cc'}\n";
  print MAIL "BCC: $FORM{'bcc'}\n";
  print MAIL "From: $FORM{'from'}\@eshal.com\n";
   
  print MAIL qq{$FORM{'text'}
  };
  close(MAIL);
  ## End of send email
 
} else { .....

Thanks to all and regards to maneshr




Avatar of maneshr
maneshr

nigg,

are you looking for something like an "Upload file & Email it as an attachment" script?

if that is the case i have a small script, which i can modify so that it works with your existing code.

let me know if that is the case.
Avatar of nigg

ASKER

Yes, this means > send mail AND attachment ro reciever!
nigg,

"..Yes, this means > send mail AND attachment ro reciever!.."
Good! can the user send any type of file as an attachment or specific file types (Eg. .doc, .pdf, .txt, .htm files only)?

Avatar of nigg

ASKER

Anything, whatever he likes, except viruses of course :-(
nigg,

"..Anything.."

Excellent!! you will have your script soon.

nigg,

do you have the CGI.pm PERL module installed on your system?

if you are not sure, try running this small script from your browser and let me know what output you get.

#!/usr/bin/perl

$|++;

print "Content-type: text/html\n\n";

use CGI;

$query=new CGI;

print "All is OK. CGI.pm does exist!!<P>\n";
ASKER CERTIFIED SOLUTION
Avatar of maneshr
maneshr

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of nigg

ASKER

CGI.pm Module installed, even in SSL Server..! Script looks interesting, I'll test it soon.
nigg,

now that you have the CGI module installed, the script that i have provided can be reduced in size by a lot.

meanwhile, let me know how the script works for you.
Avatar of nigg

ASKER

Doesn't work yet (internal Server-error)
Now we have to debug it, or maybe we try your short version with the cgi.pm module
nigg,

couple of things to check..

* did you change the location of the PERL interpreter in my script?

it should be changed from #!/usr/local/bin/perl  to #!/usr/bin/perl


* do you have the  MIME::Base64 module on your server?

use the sample script i have you above, for testing CGI.pm, and add use MIME::Base64 to confirm?

let me know how it goes.
Avatar of nigg

ASKER

Oh, Ohooo,
No, Mime::Base64 Module! Where do I get it? I try in the meantime to find it out, if not, tell me please.
Avatar of nigg

ASKER

Oh, Ohooo,
No, Mime::Base64 Module! Where do I get it? I try in the meantime to find it out, if not, tell me please.
Avatar of nigg

ASKER

Module installed, script works,but... I'm checking what's gouing on
nigg,

let me know.
Avatar of nigg

ASKER

Wow, it works.
Just two questions:
The recivier get's two attachments. One with the Stream (attachment) and one Text/Plain with nothing in it.
Secondly, if the user send two attachments, it arrives as one attachment with both attachments in one. In the Form I want to use something like that:
<input type=file name=file1>
<input type=file name=file2>
<input type=file name=file3>

Which code I have to put into the script so that it can send multiple attachments without repeating the script again and again like:
## Process the uploaded file.
$uploaded_file1=$FORM{'file1'};......

## Process the uploaded file.
$uploaded_file2=$FORM{'file2'};......

And at last: How can I learn from it?
What are the code principles?

Very nice and thanks again maneshr.
Look around for the next question.

"..and one Text/Plain with nothing in it..."

let me guess. are you using MS-Outlook (Express?) to read the email??

if so, then the second attachment (filename.ATT) is due to the problem with the email client that anything else?

".....In the Form I want to use something like that: ...."

in that case you will have to add more HTML file elements to the form first and then slightly modify the script to handle multiple files.

"..How can I learn from it?  .."
if you mean what can i learn/ have i learned from this code, then the answer is you now know how to send email attachments (of any type and hopefully any number) using PERL and CGI.

Believe me, there are users who have used PERL for some years now and still dont know how to do what you have with you!!

i dont want to call it as "assignment", cause this is too old world, but i would suggest that you take the existing code (which does not use CGI.pm) and modify it so that it works with CGI.pm.

once you have done that successfully, you are well on your way to being an experts in your own way!!

Wish you luck!!


"....What are the code principles? .."

i am not clear what you mean by the above.
Avatar of nigg

ASKER

And what about this part of the original script:
# Get the input
read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
$mailprog ="/usr/sbin/sendmail";
# Split the name-value pairs
@pairs = split(/&/, $buffer);

foreach $pair (@pairs)
{
    ($name, $value) = split(/=/, $pair);

    # Un-Webify plus signs and %-encoding
    $value =~ tr/+/ /;
    $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

    # Stop people from using subshells to execute commands
    # Not a big deal when using sendmail, but very important
    # when using UCB mail (aka mailx).
      $value =~ s/~!/ ~!/g;

    # Uncomment for debugging purposes
    # print "Setting $name to $value<P>";

    $FORM{$name} = $value;
    if ($value =~ /\<\!--\#(.*)\s+(.*)\s?=\s?(.*)--\>/) { &kill_input; }
    if ($value =~ /[;><\*`\|]/) { &kill_input; }  

And what's the part :
  ## End of send email

&Output;
} else {
print "In Else<P>\n";
}

What I have to put here? It didn't made sense to me.
nigg,

you can remove that entire part as i have moved it to a seperate sub routine (Get_Input).

# Get the input
                      read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
                      $mailprog ="/usr/sbin/sendmail";
                      # Split the name-value pairs
                      @pairs = split(/&/, $buffer);

                      foreach $pair (@pairs)
                      {
                          ($name, $value) = split(/=/, $pair);

                          # Un-Webify plus signs and %-encoding
                          $value =~ tr/+/ /;
                          $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

                          # Stop people from using subshells to execute commands
                          # Not a big deal when using sendmail, but very important
                          # when using UCB mail (aka mailx).
                            $value =~ s/~!/ ~!/g;

                          # Uncomment for debugging purposes
                          # print "Setting $name to $value<P>";

                          $FORM{$name} = $value;
                          if ($value =~ /\<\!--\#(.*)\s+(.*)\s?=\s?(.*)--\>/) { &kill_input; }
                          if ($value =~ /[;><\*`\|]/) { &kill_input; }    

                      And what's the part :
                        ## End of send email
Avatar of nigg

ASKER

Sorry but I wrote some code for multiple attachments but it seams that it doesn't work (internal Server error)

Here is what I did:

>>
## Print out any message sent with the email
if ($FORM{'text'}){
  print MAIL "Content-type: text/plain; charset=US-ASCII\n";
  print MAIL "Content-description: Mail message body\n";
  print MAIL "Content-transfer-encoding: 7BIT\n";
  print MAIL "\n";
  print MAIL $FORM{'text'}."\n";
  print MAIL "--$boundary\n";
}
if

foreach $i (0 .. 5) {
      next if (!$FORM{"file${i}"});
##Get type of file
$type = $FORM{"file${i}_content_type"}."; name=\"".
                  $FORM{"file${i}_filename"}."\"";
##Get display name       
$disp = "inline; filename=\"".
                  $FORM{"file${i}_filename"}."\"";
      
## Process the uploaded file.
$uploaded_file=$FORM{'file$'};

$tmp_uploaded_file=$FORM{'file$'};
$tmp_uploaded_file=~ s/\\/\//g;
@tmp_uploaded_file=split(/\//,$tmp_uploaded_file);

$filename = $dir_to_store."/".$tmp_uploaded_file[$#tmp_uploaded_file];

$FORM{'contents_of_the_attached_file'}=~ s/\n$//;

## Print the header for that attachment.
print MAIL "Content-type: application/octet-stream; name=\"$tmp_uploaded_file[$#tmp_uploaded_file]\"; type=$type\n";
print MAIL "Content-transfer-encoding: BASE64\n";
print MAIL "Content-disposition: $disp\n";
print MAIL "\n";

}

## Send out the contents!!
$body = encode_base64($FORM{'contents_of_the_attached_file'}); ## Use base64 for encoding the contents
print MAIL $body;
print MAIL "\n";
print MAIL "--$boundary\n";


<<

Anybody sees what's wrong here?

Thanks
"..Anybody sees what's wrong here? .."

while the loop looks ok, you are not adding the body of each file to the MAIL within the loop.

since you want 5 seperate attachments, you need to add a boundary, then the file contents, a boundary, the file contents etc.. till all files have been processed.

then you exit the loop and close the boundary.

Avatar of nigg

ASKER

Sorry but I wrote some code for multiple attachments but it seams that it doesn't work (internal Server error)

Here is what I did:

>>
## Print out any message sent with the email
if ($FORM{'text'}){
  print MAIL "Content-type: text/plain; charset=US-ASCII\n";
  print MAIL "Content-description: Mail message body\n";
  print MAIL "Content-transfer-encoding: 7BIT\n";
  print MAIL "\n";
  print MAIL $FORM{'text'}."\n";
  print MAIL "--$boundary\n";
}
if

foreach $i (0 .. 5) {
      next if (!$FORM{"file${i}"});
##Get type of file
$type = $FORM{"file${i}_content_type"}."; name=\"".
                  $FORM{"file${i}_filename"}."\"";
##Get display name       
$disp = "inline; filename=\"".
                  $FORM{"file${i}_filename"}."\"";
      
## Process the uploaded file.
$uploaded_file=$FORM{'file$'};

$tmp_uploaded_file=$FORM{'file$'};
$tmp_uploaded_file=~ s/\\/\//g;
@tmp_uploaded_file=split(/\//,$tmp_uploaded_file);

$filename = $dir_to_store."/".$tmp_uploaded_file[$#tmp_uploaded_file];

$FORM{'contents_of_the_attached_file'}=~ s/\n$//;

## Print the header for that attachment.
print MAIL "Content-type: application/octet-stream; name=\"$tmp_uploaded_file[$#tmp_uploaded_file]\"; type=$type\n";
print MAIL "Content-transfer-encoding: BASE64\n";
print MAIL "Content-disposition: $disp\n";
print MAIL "\n";

}

## Send out the contents!!
$body = encode_base64($FORM{'contents_of_the_attached_file'}); ## Use base64 for encoding the contents
print MAIL $body;
print MAIL "\n";
print MAIL "--$boundary\n";


<<

Anybody sees what's wrong here?

Thanks
maneshr,

Hi I've tried to adapt the above code to just send a mail with an attachment from the local disk (i.e. also on the server)
For some reason I can't seem to get that to work - Do you have any code that can do that?
The bit that's confusing me is the
$FORM{'contents_of_the_attached_file'}
Trying to work out how to emulate the get_Info but on a local file rather than a form submission...

Any help greatly appreciated and worth 100pts?

Cheers,

Mal
Actually ignore that - I've found a way to do what I want (not even writing the file to the server in the first place now...)

Cheers anyway,

Mal