Two things I've had to do recently

Zip

  use Archive::Zip qw(:ERROR_CODES);

  my $zip = Archive::Zip->new();

  foreach my $dir ("data", "var/log", "www/logs", "var/data") {
    next if( $zip->addTree("$from/$dir","$id/$dir") == AZ_OK );
    $aws->message("",$me,"Error adding AWS files to zip","$id $dir");
  }

  unless( $zip->writeToFileNamed("$backupdir/$id.zip") == AZ_OK ) {
    $aws->message("",$me,"Error writing zip file","$id.zip");
  }

Email with an attachment

  use MIME::Lite;

      my $msg = MIME::Lite->new(
             From     => $eam->{'notification from address'},
             To       => $to,
             Subject  => "$stitle update",
             Data     => $body
             );

      # Include list of actions
      if($sections{$s}{'instud'} && $list) {
        $msg->attach (
           Type => 'text/plain',
           Data => $list,
           Filename => "$stitle student changes.txt",
           Disposition => 'attachment'
           );
      }

      $msg->send("smtp",$eam->{'SMTP server'});