Using just Bash and Sendmail to send multiple input files and / or a pipe as attachments in an email

arober11
CERTIFIED EXPERT
Published:
Over the years I've spent many an hour playing on hardened, DMZ'd servers, with only a sub-set of the usual GNU toy's to keep me company; frequently I've needed to save and send log or data extracts from these server back to my PC, or to others, and more often than not, to do this on a regular basis.

Simple enough on an open box, just cron a script to extract and format the necessary data and either send it as a uuencoded / base 64 mmencoded attachment in an email, or simply copy / scp's the file to somewhere you can get at it e.g. a NFS or SMB mount. BUT if the server is in a DMZ you'll likely find access to any shared internal file systems and / or permission to store a private key to scp / ssh into your network not available to you, leaving email as the only practical method to send data to yourself or others being.

If the box is performing a non trivial function in the DMZ it's more than likely been hardened to some extent, and all non essential toys removed, so you'll probably find your lacking the likes of uuencode, mmencode, and perl, leaving you none of the standard mechanism to encode and to attach files to email.

You could take the quick and dirty option of just piping the data / log into an email body an hoping Outlook will treat your data kindly, and not assume it's a malicious script, or part of the email header, or in need of some character-set conversion. This approach kept me happy for a number of years, but while working with Rockroads several  year back, I was made aware of plain text mime attachments, and haven't looked back.

Plain text mime encoding attachments offer you the ability to:
Attach CSV, XML or TXT files to a mail,.

To Name the attachments, as they are appear to the recipient.

Allows you to add a BODY to the email, explaining the attachments

Offer a mechanism to specify the encoding bits and character set

Support multiple attachments in a single mail (multi-part mime)

Allow the recipient to simply save an attachments, rather than having to cut-n-paste the data out of the email.

Requires only shell and sendmail to be available to you on the box.

Anyway per the Wikipedia article, all you need to convert a plain old smtp email in to a mime encoded one is a few content type entries, in your message body, define a unique boundary separator (a string that won't appear in your data), and to add a separator and a few more content type entries between your message body and the attachments data, another separator and finally a couple of -- to mark the end of the mail.

So in a few minutes you can replace your boring old mail line in your existing script with something a bit more sophisticated, but as I've found I regularly need to send output to myself I have knocked out a few generic scripts over the years that provide a mechanism to send myself one or more file, or the output from a command.

Basically the script assumes all the command line argument along with any input piped or redirected in are files you want attached to a predefined email, to be sent to a predefined user. If you have a look through the script you'll obviously spot and realise you'll need to tweak some of the entries in the ---Tweak to suit--- block. Other than that the script is much ready to run.

One line possibly worth noting is the following line:

inputMethod=`stat -L -c %F /proc/$$/fd/0`

Open in new window


The output from the stat call, on the current processes standard input [/prod/$$/fd/0], will indicate if a file [regular file] or stream [fifo] have been piped / redirected into the script, then via a couple of additional if, then, fi blocks that input is ALSO attached to the email, permitting the script to be used in-line, anyway the script:
#!/bin/sh
                      # Purpose: email the parametrised list of files to a set user along with any content piped XOR redirected in.
                      
                      # ========================
                      DT=`date '+%Y-%m-%d'`
                      TMP_FL="/tmp/$0.$$"
                      MAIL_FL=""
                      ATTACHMENT=""
                      MIMETYPE="text/plain"
                      BOUNDARY=`date +%s|md5sum`
                      BOUNDARY=${BOUNDARY:0:32}
                      #----- Tweak to suit -----
                      MAILTO="To: arober11@somehostorother.com"
                      FROM="doNotReply@somehostorother.com"
                      REPLY_TO="doNotReply@somehostorother.com"
                      SUBJECT_LINE="Files from `uname -a` on $DT"
                      MSGBODY="Files from `uname -a` on $DT"
                      #----- CMD locations  -----
                      sendmail="/usr/sbin/sendmail"
                      sendmailParms=""
                      readlinkCMD="/usr/bin/readlink"
                      statCMD="/usr/bin/stat"
                      basenameCMD="/usr/bin/basename"
                      #----- Tweak to suit ends-----
                      
                      #----- Test if anything has been piped or directed at us -----
                      inputMethod=`$statCMD -L -c %F /proc/$$/fd/0`
                      
                      # ========================
                      # Attach file to msg
                      # ========================
                      attach_file() {
                      
                        cat >> $TMP_FL << EOF
                      
                      --$BOUNDARY
                      Content-Type: $MIMETYPE; name="$MAIL_FL"
                      Content-Transfer-Encoding: 8bit
                      Content-Disposition: attachment; filename="$MAIL_FL"
                      
                      `cat $ATTACHMENT`
                      EOF
                      }
                      
                      # ========================
                      # Create tmp msg file
                      # ========================
                      create_msg() {
                      
                        cat > $TMP_FL <<EOF
                      From: $FROM
                      `echo -e $MAILTO`
                      Reply-To: $REPLY_TO
                      Subject: $SUBJECT_LINE
                      Content-Type: multipart/mixed; boundary="$BOUNDARY"
                      
                      This is a MIME formatted message.  If you see this text it means that your
                      email software does not support MIME formatted messages, but as plain text
                      encoded you should be ok, with a plain text file.
                      
                      --$BOUNDARY
                      Content-Type: text/plain; charset=ISO-8859-1; format=flowed
                      Content-Transfer-Encoding: 8bit
                      Content-Disposition: inline
                      
                      $MSGBODY
                      
                      EOF
                      
                        while [ $# -gt 0 ]
                        do
                          if [ -r $1 -a -f $1 -a -s $1 ]
                          then
                              MAIL_FL="`$basenameCMD $1`"
                              ATTACHMENT="$1"
                              attach_file
                          fi
                          shift
                        done
                      
                        #See if anything has been piped in via STDIN, if it has add it as another attachment
                        if [ "$inputMethod" = "fifo" ]
                        then
                          cat > "${TMP_FL}.from_pipe.stdin"
                          MAIL_FL="STDIN_from_PIPE.txt"
                          ATTACHMENT="${TMP_FL}.from_pipe.stdin"
                          attach_file
                        fi
                      
                        if [ "$inputMethod" = "regular file" ]
                        then
                          cat > "${TMP_FL}.from_fl.stdin"
                          flName="`$readlinkCMD \`$statCMD  -L -c %n /proc/$$/fd/0\``"
                          MAIL_FL="`$basenameCMD $flName`"
                          ATTACHMENT="${TMP_FL}.from_fl.stdin"
                          attach_file
                        fi
                      
                        echo -e "\n--$BOUNDARY--\n" >> $TMP_FL
                      }
                      
                      # ====
                      # Main
                      # ====
                      if [ $# -gt 0 -a -f "$1" -a -r "$1" ]
                      then
                        create_msg $@
                      elif echo $inputMethod | egrep -q "character special"
                      then
                        thisCMD=`$basenameCMD $0`
                        echo
                        echo "Error: No files passed as arguments, piped in, or re-directed in :("
                        echo
                        echo "usage:    [|]$thisCMD [<file1.txt> [<file2.txt>*]] [<]"
                        echo "Purpose:  email the paramertised list of files, to a set user, along with any content piped XOR redirected in"
                        echo "examples: cat file1.txt | $thisCMD"
                        echo "                          $thisCMD file1.txt file2.txt"
                        echo "                          $thisCMD                     < file1.txt"
                        echo "          cat file1.txt | $thisCMD file2.txt"
                        echo "                          $thisCMD file1.txt file2.txt < file3.txt"
                        exit 1
                      else
                        create_msg
                      fi
                      
                      # =================
                      # Email the file(s)
                      # =================
                      $sendmail $sendmailParms -t <$TMP_FL
                      rm -f $TMP_FL*

Open in new window


Andrew Roberts, Oct 2011
0
9,769 Views
arober11
CERTIFIED EXPERT

Comments (1)

CERTIFIED EXPERT
Top Expert 2010

Author

Commented:
May also be of interest.

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.