ot: mail flag for attachment in unix
Brian K. White
brian at aljex.com
Thu Oct 1 22:03:49 PDT 2009
Dennis Malen wrote:
> Here's the last conundrum. What I now wanted to do was to send a script that
> attaches a file to the email and also writes a message in the body of the
> email.
>
> I attempted to use:
>
> uuencode /tmp/emccx.xls emcc.xls | mail -s "test3" dmalen at malen.com <tryftp
>
> If I use the right side of the pipe separately it places the contents of
> "tryftp" in the body. If I use the full line without the "<tryfile" it
> attaches "emcc.xls" to the email.
>
> When I try the entire line above, the right side of the pipe wins and just
> places the contents of "tryftp" in the body of the email without any
> attachment.
>
> Am I precluded from combining the two sides in UNIX this script or anything
> like it?
>
And now you discover just one of the mysterious reasons why "uuencode is
depreciated" and what they mean by "that is not an attachment but inline
embedding" :) They didn't say those things for no reason.
uuencode was just a way to get a single binary file across a crude
dialup serial login session, and was later (mis)used as a quick-n-dirty
way to get a binary file delivered by the email system. It only knows
how to encode a single file at a time and only contains a bare minimum
of metadata about the file. mime was invented to solve exactly the
problem you just hit.
Mime is not anything to be reluctant to deal with.
It's nothing more than a simple set of text formatting rules. A
particular pattern of text to write into a file.
You can generate that text easily with file i/o commands in filepro or
with an external shell script.
I'll write simple examples right here....
Generate a random string and say that $BOUNDARY is that string.
Now a simple mime-formatted email with some plain body text and one file
attachement would just look like this:
Tthe number and placement of "-" dashes below are important. so are some
of the blank lines, the ones that come immediately after any headers.
Headers are the lines either at the very top of the file, or at the top
of any mime-part.
For comparison, first, here is a plain email. It has no attachements and
is not mime-formatted.
This is so it's easy to see the mime bits of a mime file in the later
examples by comparison.
In all the following examples you would send this email simply by
catting it into "sendmail -t -i" ie: "sendmail -t -i < /tmp/file.txt"
or maybe from filepro: Then: system "sendmail -t -i <" < EF
That's a pretty standard command regardless what kind of email spooler
you have (even if it's not sendmail, you probably have a sendmail binary
and it probably understands "-t -i", it might not be in $PATH, so for
example on SCO Open Server which has MMDF by default not sendmail, you
had to specify the full path to the binary in it's odd place, which was
"/usr/lib/sendmail -t -i < file.txt")
The "#############" lines are not part of the file.
There can be no empty lines before the first header line.
The header lines can be in any order, To: doesn't have to be first, but
there can be no empty lines before, or within, the headers. The first
empty line starts the body content and any lines after that, even if
they look like headers, will simply be included in the body as text.
############ top of file ####
To: him at them.com
From: me at us.com
Subject: this is a plain email
This is the body text area
############ end of file ####
Now for the same file in mime formatting, no attachments yet.
It's "multi-part", with only one part.
############ top of file ##
To: him at them.com
From: me at us.com
Subject: this is a mime-formatted email
MIME-Version: 1.0
Content-Type: multipart/related; boundary=$BOUNDARY
--$BOUNDARY
This is the body text area
--$BOUNDARY--
############ end of file ##
All you did there is tell the client that the mail is formatted
according to mime standards,
MIME-Version: 1.0
define a unique string as a separator between sections,
Content-Type: multipart/related; boundary=$BOUNDARY
and then put that separator before and after the body content
--$BOUNDARY
empty line
stuff
empty line
--$BOUNDARY--
The idea is you want to be sure that separator can never accidentally
appear anywhere else in the file, so $BOUNDARY should be pretty random
and unique. at least something like a couple invocations of rand() in
filepro or $RANDOM in bash or ksh (plain sh on aix/hpux may not have
$RANDOM but you probably have ksh installed even if you never used it
before) and dont' forget if using rand() in filepro, to do a
x=rand("-1") in @once. throw the x away, you just need to do that to
seed the function. elsewhere in the table just say, maybe,
BY=rand(){rand(){rand()
and use BY as the boundary string.
Now for the same file with one attachment. All we are doing is inserting
another boundary separator, and in this case the new part also has pone
or more headers of it's own which define the metadata for the attached
file, like the files name etc...
This one doesn't require base64 encoding for simplicity, and, in case
you have no way to base64-encode your data and if your attachment file
doesn't happen to include anything but plain text, you could use this.
########### top of file ##
To: him at them.com
From: me at us.com
Subject: this is a mime-formatted email with a plain text attachement
MIME-Version: 1.0
Content-Type: multipart/related; boundary=$BOUNDARY
--$BOUNDARY
This is the body text area
--$BOUNDARY
Content-Disposition: attachment; filename=statement.txt;
This is a plain text attachment.
Since no "Content-Transfer-Encoding:" was specified, this data must be
plain, 7-bit ascii text.
No binary stuff, not even a few hplaser or ibmpro escape codes from a
captured print-to-file.
(ie, use nocodes.prt)
--$BOUNDARY--
########### end of file ##
Now the same thing, only adding that the attachment file has binary data
in it and so must be base64 encoded.
You need some way to base64-encode your data for this.
There are many possible ways to get that. There are any number of
programs that you might or might not have on your box, or could maybe
find even if you don't have a compiler. openssl, mimeencode (part of a
package called metamail), mcrypt,
You have perl, perhaps you also have the mime module:
perl -pe 'use MIME::Base64; $_=MIME::Base64::encode($_);' <file.csv
>file.csv.b64
You might even have a binary called simply base64. There is a simple
base64.c file from fourmilab thats so old that even though you don't
have a compiler, maybe you can find a binary someone else compiled for
your platform.
I believe someone here, Nancy? Laura? once said they made a base64 call
table in native filepro processing. That would be ideal.
########### top of file ##
To: him at them.com
From: me at us.com
Subject: this is a mime-formatted email with abinary attachement
MIME-Version: 1.0
Content-Type: multipart/related; boundary=$BOUNDARY
--$BOUNDARY
This is the body text area.
--$BOUNDARY
Content-Disposition: attachment; filename=statement.csv;
Content-Transfer-Encoding: base64
<the base64 data goes here. For instance if this were a shell script
building this email, then at this point I might run the perl command
above and put the data here instead of capturing it to file.csv.b64>
--$BOUNDARY--
########### end of file ##
"--$BOUNDARY" denotes the beginning of each new part, which also
serves as the end of the previous part.
"--$BOUNDARY--" denotes the end of the last part and is generally the
end of the file.
A csv file is probably plain-text enough that you may not have to base64
encode it.
If you had taken a hplaser print-to-file, and converted it to a pdf with
ghostpdl, then you would need to base64 encode the pdf.
An EDI file that has special field and record delimiter characters, or
lines longer than 76 characters, needs to be base64 encoded.
Here is a real working direct example with actual commands and sample
data. You can actually cut & paste this entire thing in one shot right
into a shell prompt if you want and, as long as you have a sendmail in
your path and your networking is working, it will actually send you a
mail. Take everything from cat, to one line past the last %%EOF
Edit the to & from emails as desired.
cat <<%%EOF |sendmail -t -i
To: dmalen at malen.com
From: brian at aljex.com
Subject: this is a mime-formatted email with a plain text .csv attachement
MIME-Version: 1.0
Content-Type: multipart/related; boundary=gfkfgjyyfgfyre53467rutyfy5
--gfkfgjyyfgfyre53467rutyfy5
Attached is a .csv table summary of your account status.
--gfkfgjyyfgfyre53467rutyfy5
Content-Disposition: attachment; filename=statement.csv;
Content-Type: text/csv
"Name","Account","Invoice","Amount","Amount Due","Date Due"
"A Corp","0001","3001","100.00","100.00","20090909"
"A Corp","0001","3002","1000.00","0.00","20090910"
"A Corp","0001","3053","400.00","0.00","20090915"
"A Corp","0001","3103","50.00","50.00","20090915"
"A Corp","0001","4245","750.00","250.00","20091002"
--gfkfgjyyfgfyre53467rutyfy5--
%%EOF
All that said. I'd just use lightmail. This is exactly exactly exactly
the task it was designed to do, and you already own it.
The main reason to construct the mail file yourself is so you can put
anything you want into the mail headers instead of being limited to
whatever your mta (mutt, lightmail, mpack, mail, pine, etc...) happens
to offer.
--
bkw
More information about the Filepro-list
mailing list