#!/usr/bin/perl my $rcsid = '$Id: msend,v 1.7 2002/07/19 20:11:11 vogelke Exp $'; =head1 NAME msend =head1 SYNOPSIS msend [-s subj] -a file [-a file ...] [-t textfile] to [to ...] msend [-s subj] -a file [-a file ...] to [to ...] < textfile msend [-s subj] -A to [to ...] < attachment-list msend -v =head1 DESCRIPTION Reads files from the command line, and writes a MIME-formatted mail message to stdout. The "mutt" mailer does a similar job, but doesn't give me a choice about how it encodes files. The default MIME-type is 'application/octet-stream', and the default encoding used is 'base64'. The MIME-type and encoding used depends on the file extension; see the "filetype" and "encoding" variables. Requires the MIME::Lite module. =head1 OPTIONS -a file is one or more attached file(s). -A reads a list of attached files from stdin. -s subj is an optional message subject. -t textfile reads the start message from a file. -v prints the version and exits. to is one or more email recipients. textfile is optional text to start the email message. =head1 EXAMPLES msend -a file1.txt -a file2.pl -a file3-1.1.tar.gz you@your.host will produce output looking like this: Content-Transfer-Encoding: binary Content-Type: multipart/mixed; boundary="_----------=_102683910912380" MIME-Version: 1.0 X-Mailer: MIME::Lite 2.117 (F2.6; B2.12; Q2.03) To: you@your.host Subject: No subject This is a multi-part message in MIME format. --_----------=_102683910912380 Content-Disposition: inline Content-Length: 31 Content-Transfer-Encoding: binary Content-Type: text/plain Here are the files you wanted. --_----------=_102683910912380 Content-Disposition: inline; filename="file1.txt" Content-Transfer-Encoding: 8bit Content-Type: text/plain; name="file1.txt" Contents of file1.txt go here --_----------=_102683910912380 Content-Disposition: inline; filename="file2.pl" Content-Transfer-Encoding: 8bit Content-Type: text/x-perl; name="file2.pl" #!/bin/perl # some perl script goes here. --_----------=_102683910912380 Content-Disposition: inline; filename="file3-1.1.tar.gz" Content-Transfer-Encoding: base64 Content-Type: application/octet-stream; name="file3-1.1.tar.gz" H4sIAJplKj0AA+xd+0PbRvLvr/iv2ChOAi1+P+gXjBqXOCl3BPiC016u6lHZ ... GTyDZ/AMnsEzeAbP4Bk8g2fwDJ7BM3gGz+AZPIPn0Of/A3Gim4YA4AEA --_----------=_102683910912380-- =head1 AUTHOR Karl Vogel Sumaria Systems, Inc. Based on mimesend by Eryq, eryq@zeegee.com, 8 Jan 1997 =cut # To generate manpage: # pod2man -c 'User docs' -r "`date`" -d version msend #--------------------------------------------------------------------- use strict; use warnings; use subs qw(usage version); use File::Basename; my ($myname) = basename ($0, ".pl"); #--------------------------------------------------------------------- # Set the MIME-type and encoding based on file extension, if any. my $deftype = 'application/octet-stream'; my $defencode = 'base64'; # Generated by mime2perl my %filetype = qw( PS application/postscript Z application/x-compress ai application/postscript bat text/plain bmp image/x-ms-bmp c text/x-csrc c++ text/x-c++src cc text/x-c++src cgi text/x-perl cpio application/x-cpio cpp text/x-c++src csh text/x-csh css text/css cxx text/x-c++src desc text/plain eps application/postscript gif image/gif gz application/x-gzip h text/x-chdr h++ text/x-c++hdr hh text/x-c++hdr hpp text/x-c++hdr htm text/html html text/html hxx text/x-c++hdr jpe image/jpeg jpeg image/jpeg jpg image/jpeg js text/x-javascript ksh text/x-ksh latex text/x-latex m1v video/mpeg man text/x-troff-man me text/x-troff-me mp2 video/mpeg mpa video/mpeg mpe video/mpeg mpeg video/mpeg mpg video/mpeg ms text/x-troff-ms pbm image/x-portable-bitmap pdf application/pdf pgm image/x-portable-graymap php text/x-httpd-php pht text/x-httpd-php phtml text/x-httpd-php pl text/x-perl pm text/x-perl png image/png pnm image/x-portable-anymap ppm image/x-portable-pixmap ps application/postscript py text/x-python rdf application/xml roff text/x-troff sh text/x-sh shar text/x-shar t text/x-troff tar application/x-tar tar.gz application/x-tar-gz tcl text/x-tcl tex text/x-tex texi text/x-texinfo texinf text/x-texinfo txt text/plain tgz application/x-tar-gz tif image/tiff tiff image/tiff tk text/x-tcl tr text/x-troff ustar application/x-ustar xbm image/x-xbitmap xml text/xml xpm image/x-xpixmap xsl application/xml xwd image/x-xwindowdump zip application/x-zip-compressed ); my %encoding = qw( PS base64 Z base64 ai base64 bat quoted-printable bmp base64 c 8bit c++ 8bit cc 8bit cgi 8bit cpio base64 cpp 8bit csh 8bit css 8bit cxx 8bit desc 8bit eps base64 gif base64 gz base64 h 8bit h++ 8bit hh 8bit hpp 8bit htm quoted-printable html quoted-printable hxx 8bit jpe base64 jpeg base64 jpg base64 js 8bit ksh 8bit latex 8bit m1v base64 man 8bit me 8bit mp2 base64 mpa base64 mpe base64 mpeg base64 mpg base64 ms 8bit pbm base64 pdf base64 pgm base64 php 8bit pht 8bit phtml 8bit pl 8bit pm 8bit png base64 pnm base64 ppm base64 ps base64 py 8bit rdf base64 roff 8bit sh 8bit shar 8bit t 8bit tar base64 tar.gz base64 tcl 8bit tex 8bit texi 8bit texinf 8bit txt quoted-printable tgz base64 tif base64 tiff base64 tk 8bit tr 8bit ustar base64 xbm base64 xml 8bit xpm base64 xsl base64 xwd base64 zip base64 ); # End of code by mime2perl # Usage: @ARGV or usage("no args"); # Get args: my @files = (); my @to = (); my $subj = "No subject"; my $exten = ''; my $Aflag = 0; my $tfile = ''; ARG: while (@ARGV) { $_ = shift @ARGV; /^-s(.*)/ and do { $subj = $1 || shift @ARGV; next ARG; }; /^-a(.*)/ and do { push @files, $1 || shift @ARGV; next ARG; }; /^-t(.*)/ and do { $tfile = $1 || shift @ARGV; next ARG; }; /^-A/ and do { $Aflag++; next ARG; }; /^-v/ and do { my $vers = version(); warn "$vers\n"; exit (0); }; /^-.*/ and do { usage ("unrecognized option: $_"); }; push @to, $_; } # Verify destination. $#to >= 0 or die "$myname: missing recipient(s)\n"; # If anything is coming in via STDIN, # and we're not using it for a list of attachments, # use it for the leading text in the email. # # If the -t option was used, it overrides stdin. my $intro = "Here are the files you wanted.\n"; if (-f STDIN || -p STDIN) { if ($Aflag) { chomp (@files = ); } else { undef $/; $intro = ; } } if (length ($tfile)) { open (F, "< $tfile") || die; $intro = do { local $/; }; close (F); } # Verify files. $#files >= 0 or die "$myname: no files specified!\n"; # Create a new multipart message. # # We don't include the MIME stuff until here because we don't # need it if we're just printing the version or usage. # A "use" statement runs the equivalent of a BEGIN block, # so "require" saves some startup time. # # FIXME: the "Encoding" line is a hack to prevent "binary" from # being used in the overall content-type-encoding: header # line. "Binary" causes problems when the resulting # message is run through hypermail. Easiest fix is to # simply delete the content-type-encoding: header. require MIME::Lite; my $msg = new MIME::Lite To => join (', ', @to), Subject => "$subj", Datestamp => 0, Encoding => '8bit', Type => 'multipart/mixed'; # Add attachments. attach $msg Type => 'TEXT', Data => $intro; foreach (@files) { # get the filename extension, and remove the leading dot. # fileparse is fussy; use single quotes for the suffix type. (undef,undef,$exten) = fileparse($_, '\.[^\.]*'); $exten = substr ($exten, 1) if length ($exten); attach $msg Type => ($filetype{$exten} || $deftype), Encoding => ($encoding{$exten} || $defencode), Path => $_, Filename => basename($_); } # Output the message to stdout print "Reply-To: $ENV{'REPLYTO'}\n" if $ENV{'REPLYTO'}; $msg->print(\*STDOUT); exit (0); #--------------------------------------------------------------------- # Print a usage message from the comment header and exit. sub usage { my ($emsg) = @_; require Pod::Usage; import Pod::Usage qw(pod2usage); warn "$emsg\n"; pod2usage(-verbose => 1); } #--------------------------------------------------------------------- # Return the current version. sub version { $_ = $rcsid; s/,v / /; @_ = split; return "$_[1] v$_[2] $_[3] $_[4]"; }