#!/usr/bin/env perl use strict; use warnings; use MIME::Base64 qw(encode_base64); use File::Basename qw(basename); sub usage { die "Usage: $0 --to TO --from FROM --subject SUBJECT --body BODY file1 [file2 ...]\n"; } my ($to, $from, $subject, $body); my @files; while (@ARGV) { my $a = shift @ARGV; if ($a eq '--to') { $to = shift @ARGV // usage(); } elsif ($a eq '--from') { $from = shift @ARGV // usage(); } elsif ($a eq '--subject') { $subject = shift @ARGV // usage(); } elsif ($a eq '--body') { $body = shift @ARGV // usage(); } else { push @files, $a; } } usage() unless defined $to && defined $from && defined $subject && defined $body; usage() unless @files >= 1; my $boundary = "BOUNDARY_" . time . "_" . int(rand(1_000_000)); print "From: $from\n"; print "To: $to\n"; print "Subject: $subject\n"; print "MIME-Version: 1.0\n"; print "Content-Type: multipart/mixed; boundary=\"$boundary\"\n\n"; print "--$boundary\n"; print "Content-Type: text/plain; charset=UTF-8\n\n"; print "$body\n\n"; for my $file (@files) { if (!-f $file) { warn "Skipping missing file: $file\n"; next; } my $fname = basename($file); open(my $fh, "<", $file) or die "Cannot open $file: $!"; binmode($fh); local $/; my $raw = <$fh>; close($fh); my $b64 = encode_base64($raw, ""); # no newlines print "--$boundary\n"; print "Content-Type: application/octet-stream; name=\"$fname\"\n"; print "Content-Disposition: attachment; filename=\"$fname\"\n"; print "Content-Transfer-Encoding: base64\n\n"; print $b64; print "\n\n"; } print "--$boundary--\n";