Attach a binary file to email in a script

Hi,
I am trying to get an email sent out by the unix ( aix ) system that has a .gz file attached to it.
I can get the attachment, but it's not working when being looked at from outlook.
I think there is a problem because of the way I am doing it, and the fact that it's binary.

I am trying to use mime type to attach it. This works with ascii files but not with the binary .gz file. I am thinking it's because of the way I am catting the file into the message. Not sure.
Is there a better way to do this ?

echo "To: me" >$msgfile
echo "Subject: informix specific files for DR `date` " >>$msgfile
echo "Mime-Version: 1.0" >> $msgfile
echo "Content-Type: multipart/mixed; boundary=\"DMW.Boundary.605592468\"" >>$msgfile
echo "" >>$msgfile
echo "--DMW.Boundary.605592468" >>$msgfile
echo "Content-type: application/octet-stream; name=\"drfile.gz\"" >>$msgfile
echo "Content-Disposition: attachment;filename=\"drfile.gz\"" >>$msgfile
echo "Content-Transfer-Encoding: 7bit" >>$msgfile
echo "" >>$msgfile
cat drfile.gz >>$msgfile
echo "--DMW.Boundary.605592468--" >>$msgfile
cat $msgfile|/usr/lib/sendmail -t

Thanks,
floyd

You should convert the file to mime format with b64encod(e), and I think that you need a blank line after the "Content-Transfer-Encoding" line.

Thanks.
I tried to do
uuencode -m file.gz and pipe that to mailx, but it doesn't work.
Looks like it needs an output file as an argument, but it still only outputs garbled stuff to the standard out.

uuencode file.gz file.gz | mailx .....

So I ran

 uuencode -m test.tar.gz test.tar.gz  | mailx  floydw@mail.org 

and I got an email that looked like this:

begin-base64 644 test.tar.gz
H4sICChVQ0sAA3Rlc3QudGFyAOz9W5MjS3aYC+p5/wo85jycasQ9QjY2ZjwSpcMxSuSQLdnMvJRl
4pJVrURlCkBVo//9QbhHeEQ4Au5Y3wKK3cUNaSeNm3vF8su6+bp++sN6/3n79W1z+MN/eNRvmS+r
olj8h+VymeWZ/Z+J/d/73yJJsnRZFmmWZotlkqdJ9R8WxcNWNPp9Pxyf9+elHDbfjvu/rLbX/jv7
f7/+nW4f7n/+jfw+Dfe/ev+2/fr66XDcvL09f0qXyfL8/4vlMk2UOM4fKvN8cXFE5z9J+yvL1Lv/
KqmK/7BY3mWHkV9///v392Povzv85Xwwu+v/97/R+/8/tL/f/l/n3+LL++H47Xm3Wfw/z7/f9B+1
RHiHD5nVrZ+Pd1vZH79vFv/v52+LRbFYLv9jmvzHM8H+/b/+cdHyy73W+3542/zYvN1rycWn7NPy
091W93b4+HGvpX1Zfz38r+XC/c6sU9bbdbparrdJ2TwvZn4tp/54Hf7359Xx64+N/VRy+al0k2Vp
ui6ln0rnPrV6rjfVeu5TX78dN/tvz2+fu++NP5Vd+9RzIf1UPv7UqqqS9ap4Of95aaq5T/3Lvyaf
/7Q99F+afKq48qnVupF+qrzyqU2ylH6quvKpbbqVfqqe/9R6mW+kn2pmP7VplkU9/6n06qdGRzL5
VDJP7cFPJfOfStdXiCHwqXT+U/kyEX8qm/9Uka6knyovP1U16+SlrOWfymc+tU1WdTXLg6FP1eNV
WXbOnsvqJS1mV/XyvPpf3z8GMTP5VD7/qefN7KqCnypmP7UqXzLxp8rZT62XxSxdBT9VzX/qucnF
n6pnPlU0xSaZ5cH1S/L56/Y0f4PN3KfWz5t0ltrXL+nVTzXLuU9tspd0VuOsX7Lrn0pmP7U6U/z8
.......
echo "subject: Something" ; cat $text_mail ; uuencode file.gz file.gz) | /usr/sbin/sendmail john@doe.nl

... which is perfectly fine, since that is how it is supposed to look.

You'd then proceed to save the message and uudecode it to obtain the "test.tar.gz" file.

tyler_durden

I think I am getting the gist.
I am able to encode and decode a file on Unix, and it works fine.
However, if I mail the encoded file, save that email message, ftp it back to unix and then try and decode it, I can't. It says Line too long. ( I got rid of the extra email header stuff ).
I think it may have to do with the extra ^M ( \r\n ) that gets put on in the windows email client or system.
I tried to get rid of that also, no joy.

Any further ideas about that ??

Thanks,
Floyd

Save in Windows ?

Not sure how you uudecode it, but if I -
(a) mail an attachment to my own Linux user
(b) view it using "mail" command
(c) save the email, as a text file, in my current directory in Linux
(d) run uudecode on that text file

then I get the original attachment "test.tar.gz" back. Even when the headers and all are seen in the text file.

Shown below -

$                                                    
$ mail                                               
...
...
& p                                                    
Message  1:                                            
...
...
Content-Type: text/plain; charset=us-ascii               
Status: R                                                

begin-base64 664 test.tar.gz
H4sICFlkQ0sAA3Rlc3QudGFyAO1YfWwcRxWfXe85l8RO/JGQtDbVqTgQS/h6
556/oEj+TOLGsV3bDW7TZHN3u/YevS/d7RW7ikSTiymuY2EBriKBkCIh1D9S
iapVZamhSnFpqOCPAP9EAUEBFy7ERa0aQv4oWd6bmd2b27hFgIpAuneanfnN
/Oa9t2
...
...
vtR0VDWNXPJxf2SG0P862MyylKUsZSlLWcpSlrKUpSxlKUtZylKWspTlf1D+
AenpsMcAKAAA                                                
====

& save myfile
"myfile" [New file] 74/3938
& q
$
$ # check if the email was saved as "myfile" in current directory
$ ls
myfile
$
$ # uudecode myfile now
$ uudecode myfile
$
$ # now check again
$ ls
myfile  test.tar.gz
$
$

Not sure why you'd want to "save email in Windows, ftp back to *nix, uudecode back to original attachment".
If you are able to send the view the attachment correctly (in Windows), then your purpose is served, isn't it ?

In any case - I do not have that kind of set up (emails to Internet addresses) in my Linux box, but I'd say try this -

(1) Send the attachment to a *nix user in your *nix box.
(2) Send the same email to an Internet address.
(3) Download, save and ftp the email back to *nix.
(4) Save the email sent in Step (1) to a local directory in *nix.
(5) Do a diff between the files in (3) and (4). Quite possibly, the Windows mail agent adds some extra stuff.

tyler_durden

i remember wrestling with this problem years ago...

in order to receive the email, and see the "uuencode" output as an attachment, I believe you needed something like this:

(
cat << EOF
TO: joker@batman.com
FROM: riddler@chaos.com
SUBJECT: bananas rochester
CONTENT-TYPE: html/text;

I will crush you.

CONTENT-TYPE: binary;

EOF

uuencode chicken_bomb.gz  not_a_chicken_bomb.gz

) | /usr/lib/sendmail -t

That 'content-type: binary;' is wrong but . . .

there was some way of telling sendmail that the second "content" was an attachment.
Darned if I can recall what it was or find it though....

But the email ~did~ show up with the standard attachment, and not the uuencoded stuff.

But if someone could check the output of the perl module: Sendmail.pm then we'd have the answer.

This has worked for me but it's been a while since I've used it. You'll want to at least modify the To/From lines:

tmpfile=/tmp/mimetmp.$$
basefile=`basename $your_file`

cat > $tmpfile << EOT
From: there@there.com
To: here@here.com
Subject: The subject
MIME-Version: 1.0
Content-Type: multipart/mixed;boundary="mime-attachment-boundary"

--mime-attachment-boundary
Content-Type: text/plain; charset="iso-8859-1"
Content-Transfer-Encoding: 8bit

A MIME encoded file is attached called: $basefile
--mime-attachment-boundary
Content-Type: application/octet-stream; name="$basefile"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="$basefile"
EOT

mimencode $your_file >> $tmpfile
echo --mime-attachment-boundary-- >> $tmpfile
/usr/lib/sendmail -t < $tmpfile
rm $tmpfile

See more details in Chapter 23 of "Expert Shell Scripting"

You can try this, should work for html/txt message body with multiple attachments

#!/usr/bin/bash
#
#    send_mail_html.sh (send_mail_html/txt_body_plus_attachments) 
#U
#U  Usage:
#U         ##SCRIPT_NAME## "<TO:email1@sample.com,email2@sample.com>" "<Subject:>" "<html_BODY_file>" "<File-1>" "<File-2>" "<File-nth>"
#U
#
Script_name=$(echo $0 | tr '\/' '\n' | tail -1)

########################################
#                                      #
#
Usage_F(){ ###+ START
        echo $1
        echo "Incorrect Syntax, missing arguments.  Exiting ...";
        grep ^#U $0 | sed -e s/^#U// -e s/##SCRIPT_NAME##/$Script_name/;
        exit 1;
} ###+ END Usage_F
#                                      #
########################################

[ $# -lt 4 ] && { Usage_F; }

TO="$1"
SUBJECT="$2"
BODY="$3"
FILE_ATTACHMENT="$4"
BOUNDARY="-"
FROM="email_from@goes-here.us"

#M0 From:##FROM##
#M0 To:##TO##
#M0 Mime-Version:1.0
#M0 Content-Type:Multipart/mixed;boundary=Message-Boundary-##BOUNDARY##
#M0 Subject:##SUBJECT##

#M1 
#M1 --Message-Boundary-##BOUNDARY##
#M1 Content-type:text/html;charset=ISO-8859-1
##US-ASCII
#M1 Content-transfer-encoding: 7BIT
#M1 Content-Disposition:inline
#M1 Content-Description: Read Me First
#M1 
###_GET_HTML_CONTENT_HERE

#M2 --Message-Boundary-##BOUNDARY##
#M2 Content-type:Application/Octet-Stream;name=##FILE_ATTACHMENT##;type=Binary
#M2 Content-disposition:inline;filename=##FILE_ATTACHMENT##
#M2 Content-transfer-encoding: X-UUencode
#M2 Message-Boundary-##BOUNDARY##
#M2 
###_uuencode ./${FILE_ATTACHMENT} ${FILE_ATTACHMENT} >>mail_out

###_Sample of mailx sending attachment with message in text format (NO HTML)
##M TO="##TO##"
##M SUBJECT="##SUBJECT##"
##M FILE_ATTACHMENT="##FILE_ATTACHMENT##"
##M cat <<EOF | ( cat -; uuencode ./$FILE_ATTACHMENT $FILE_ATTACHMENT; ) | mailx -s "$SUBJECT" "$TO"
##M --Body_here_optional--

TMP=_tmp_mail_out_$(date '+%H%M%S%Y%m%d')
egrep '^#M0|^#M1' $0 | sed -e s/^#M.\ // -e s/##FROM##/$FROM/ -e s/##TO##/$TO/ -e s/##SUBJECT##/$SUBJECT/ -e s/##FILE_ATTACHMENT##/$FILE_ATTACHMENT/g -e s/##BODY##/$BODY/ >$TMP
cat $BODY >>$TMP

shift 3;
while [ ! -z $1 ]; do
        echo $1
        if [ -f $1 ]; then
                grep ^#M2 $0 | sed -e s/^#M.\ // -e s/##FROM##/$FROM/ -e s/##TO##/$TO/ -e s/##SUBJECT##/$SUBJECT/ -e /##FILE_ATTACHMENT##/$1/g -e s/##BODY##/$BODY/ >>$TMP
                uuencode ./$1 $1 >>$TMP
        else
                rm -f $TMP; Usage_F;
        fi
        shift
done

/usr/lib/sendmail "$TO" <$TMP
rm -f $TMP

exit 0

Thanks for all the replies !!
I think I got it worked out.
The remaining crux of my problem was what windows was doing to the file. once I stripped the \r off of each line, and added a \n to the last character of the file ( that windows stripped off ), it seemed to work fine.

Great stuff, great forum.

thanks again !!
Floyd

---------- Post updated at 06:05 PM ---------- Previous update was at 05:40 PM ----------

Quirkasaurus,
Just wanted to let you know, that this is the best one yet.
I didn't even have to do any decoding when it went back over to the unix side. Worked like a charm.

Thanks much.

Floyd

Similar thread: sendmail with attachments

That script may work, but that is one of the worst paradigms I have ever seen...

The whole thing could/should have been a lot cleaner using "HERE" documents:

cat << EOF
 
Content-type:Application/Octet-Stream;name=$FILE_ATTACHMENT;type=Binary
Content-disposition:inline;filename=$FILE_ATTACHMENT
Content-transfer-encoding: X-UUencode
.
.
.
etc...
 
EOF

---------- Post updated at 09:52 AM ---------- Previous update was at 09:23 AM ----------

Okay, having said that, here is my revised script. The gallery can judge which program is more easily understood.

#!/bin/ksh
#----------------------------------------------------------------------#
# FILE:    duck                                                        #
# AUTHOR:  da quirkasaurus                                             #
# CREATED: Wed Jan  6 12:27:42 EST 2010                                #
# PURPOSE: email with attachments.                                     #
#                                                                      #
#----------------------------------------------------------------------#
 
 
clean_exit()
{
 
print usage: $0 to subject html_body_file attachment_file_nm
 
exit 0
 
}
 
 
 
#----------------------------------------------------------------------#
# Argument check.                                                      #
#----------------------------------------------------------------------#
if [[ $# -ne 4 ]]; then
  clean_exit
fi
 
 
TO="$1"
SUBJECT="$2"
BODY="$3"
FILE_ATTACHMENT="$4"
 
hostname=$( hostname )
 
FROM="${LOGNAME}@$hostname"
 
 
#----------------------------------------------------------------------#
# Verify file existance.                                               #
#----------------------------------------------------------------------#
if [[ ! -f "$BODY" ]]; then
  print html text file: $BODY not found
  exit 1
fi
 
if [[ ! -f "$FILE_ATTACHMENT" ]]; then
  print attachment file: $FILE_ATTACHMENT not found
  exit 1
fi
 
 
(
#----------------------------------------------------------------------#
# Create message header.                                               #
#----------------------------------------------------------------------#
cat << EOF
TO:${TO}
FROM:${FROM}
Mime-Version:1.0
Content-Type:Multipart/mixed;boundary=Message-Boundary-
Subject:${SUBJECT}
 
EOF
 
#----------------------------------------------------------------------#
# Print HTML content.                                                  #
#----------------------------------------------------------------------#
cat << EOF
 
--Message-Boundary-
Content-type:text/html;
Content-transfer-encoding: 7BIT
Content-Disposition:inline
Content-Description: Read Me First
 
EOF
 
cat $BODY
 
#----------------------------------------------------------------------#
# Create attachment.                                                   #
#----------------------------------------------------------------------#
cat << EOF
--Message-Boundary-
Content-type:Application/Octet-Stream;name=${FILE_ATTACHMENT};type=Binary
Content-disposition:inline;filename=${FILE_ATTACHMENT}
Content-transfer-encoding: X-UUencode
Message-Boundary-
 
EOF
 
#----------------------------------------------------------------------#
# Attach file.                                                         #
#----------------------------------------------------------------------#
uuencode ${FILE_ATTACHMENT} ${FILE_ATTACHMENT##*/}
 
) | /usr/lib/sendmail -t
 
exit 0
 

I am trying to use the script but it does not send the attach on the email, I get the attach on the email but it empty.

How can I use that attach in the body of the HTML?

Thanks!

salu2
masch