Operating System - OpenVMS
1823143 Members
3474 Online
109647 Solutions
New Discussion юеВ

Usinge MIME within a PIPE

 
SOLVED
Go to solution
Jack Trachtman
Super Advisor

Usinge MIME within a PIPE

For years I've created DCL scripts with embedded MIME cmds to create files with attachments. I'd like to be able to include a small amount of text in the body of the msg. I tried the following test:

$ PIPE WRITE SYS$OUTPUT "Test" | ( MIME ; NEW mimefile.out ; ADD attachment ; SAVE ; EXIT )

The mimefile.out contains an "inline" section for the msg text, but no msg. I'm guessing that after the MIME NEW cmd opens its editor, the EOF from the incoming PIPE connection causes the editor to exit w/o saving the text.

Any suggestions? (I've looked at SFF (Send From File), but that would require much more coding)

TIA
17 REPLIES 17
Steven Schweda
Honored Contributor

Re: Usinge MIME within a PIPE

I've probably never used MIME to send
anything (it has enough problems unpacking
messages), so I know nothing, but the HELP
(NEW /EDIT) suggests that NEW /NOEDIT might
be useful. Otherwise, if it's using
MAIL$EDIT, you might be able to define that
(in this context) to something artificial
which would do what you want.
Joseph Huber_1
Honored Contributor

Re: Usinge MIME within a PIPE

( MIME ; NEW mimefile.out ; ADD attachment ; SAVE ; EXIT )

this is sequentially executing the DCL commands MIME, then NEW, ADD, SAVE, EXIT,
NOT the MIME sub-commands desired.
The pipe text "test" will be input to MIME, interpreted as an unknown command by MIME.

What are You trying to achieve ?
If you want to send mail attachments from a DCL command-line, then there were several threads here in ITRC forum, on dcl.openvms.org,
or my version at
http://wwwvms.mpp.mpg.de/~huber/util/com/send_attach.com

Basically, you have to create a dummy/empty mime output file, and a command-file containing the ADD commands and the final SAVE,
then MAIL this resulting MIME output file.
http://www.mpp.mpg.de/~huber
Jack Trachtman
Super Advisor

Re: Usinge MIME within a PIPE

Joseph - you're right, my example was invalid for a PIPE stream.

But I've found a solution (though not as efficient as I'd hoped), which does allow me to include a msg body along w/an attached file:

$ CREATE MSGBODY.TXT
THIS IS THE BODY
$ WS :== WRITE SYS$OUTPUT
$ PIPE ( WS "NEW MIME.OUT" ; -
WS "INCLUDE MSGBODY.TXT" ; -
WS "EXIT" ; -
WS "ADD attachement " ; -
WS "SAVE" ; -
WS "EXIT" ) | MIME
$ MAIL MSGBODY.TXT ...
John Gillings
Honored Contributor

Re: Usinge MIME within a PIPE

Jack,

I'm not certain I've worked out what you want "Test" to do. You can get somewhere with:

$ WO="WRITE SYS$OUTPUT"
$ PIPE (wo "NEW/NOEDIT mimefile.out" ; -
wo "ADD attachment" ; -
wo "SAVE" ; -
wo "EXIT") | -
MCR MIME

This is equivalent to:

$ MCR MIME
$ DECK
NEW/NOEDIT mimefile.out
ADD attachment
SAVE
EXIT
$ EOD

The difference is the PIPE construct allows you to modify the commands with symbol substitutions.

Note that the ADD command expects a filespec. I think you can do what I think you want, but it's a bit weird. Note that the attachments don't get processed until after the SAVE command. Try this:

$ WO="WRITE SYS$OUTPUT"
$ PIPE (WO "Line 1" ; WO "Line 2") |-
(WO "NEW/NOEDIT mimefile.out" ;-
WO "ADD SYS$PIPE" ;-
WO "SAVE" ;-
COPY SYS$PIPE SYS$OUTPUT) |-
MCR MIME

So, the trick is the SAVE command immediately follows ADD SYS$PIPE, then you send the output from the first pipe stage as the text of the attachment. This may seem a bit backwards, but think carefully about where the SYS$PIPEs get evaluated and you may make sense of it.

If the segments get too complex, remember your pipe segments can execute command procedures, so you could write:

$ PIPE @GEN_CONTENT | @MIME_COMMANDS | MCR MIME

I often do this with a single procedure, using the first parameter as a flag to choose an execution path. For example:

$ self=F$PARSE(";",F$ENVIRONMENT("PROCEDURE"))
$ IF F$EXTRACT(0,1,p1).EQS."#"
$ THEN
$ target=p1-"#"
$ GOTO 'target'
$ ENDIF
$
$ PIPE @'self' #CONTENT | @'self' #CMDS | MCR MIME
$ EXIT
$
$ CONTENT:
$ WRITE SYS$OUTPUT F$TIME()
$ WRITE SYS$OUTPUT "Line2"
$ WRITE SYS$OUTPUT "Line3"
$ EXIT
$
$ CMDS:
$ WRITE SYS$OUTPUT "NEW/NOEDIT mimefile.out"
$ WRITE SYS$OUTPUT "ADD SYS$PIPE"
$ WRITE SYS$OUTPUT "SAVE"
$ COPY SYS$PIPE SYS$OUTPUT) |-
$ EXIT

Not really necessary in this case, as there are no loops, conditionals or other complexities in the pipe segments, but it illustrates the principle.
A crucible of informative mistakes
John Gillings
Honored Contributor

Re: Usinge MIME within a PIPE

Jack, (was I too late?)

>(though not as efficient as I'd hoped),

Don't be so sure. PIPE is often significantly more expensive than using temporary files. Personally I hate using scratch files because you spend too much code cleaning them up, and dealing with failure paths, making sure files are closed, etc...

However, if you must make a temporary, there are new tools to help deal with issues of uniqueness, process threads and recursion. Here's what I usually do:

at the start of the procedure:

$ self=F$PARSE(";",F$ENVIRONMENT("PROCEDURE"))
$ name=F$PARSE(self,,,"NAME")
$ u=F$PARSE(F$UNIQUE(),"SYS$SCRATCH:.TMP;")

generate filenames:

$ tmp=F$PARSE(".''name'_TMP;",u)
$ t1=F$PARSE(".''name'_T1;",u)
$ msgbody=F$PARSE(".''name'_MSGBODY;",u)

at exit look for and delete all temp files from this invokation:

$ ufiles=F$PARSE("."+name+"_*;*",u)
$ IF F$SEARCH(ufiles).NES."" THEN DELETEX 'ufiles'

A crucible of informative mistakes
Jack Trachtman
Super Advisor

Re: Usinge MIME within a PIPE

John,

This is a cool idea:

$ WO="WRITE SYS$OUTPUT"
$ PIPE (WO "Line 1" ; WO "Line 2") |-
(WO "NEW/NOEDIT mimefile.out" ;-
WO "ADD SYS$PIPE" ;-
WO "SAVE" ;-
COPY SYS$PIPE SYS$OUTPUT) |-
MCR MIME

but unfortunately not quite what I need.

Let me start over w/an interactive example:

$ MIME
MIME> NEW mime.out
* INSERT
(editor opens and accepts input until)
^Z
* EXIT
MIME> ADD attached.file
MIME> SAVE
MIME> EXIT
$

Examining the mime.out file shows that everything entered into the editor goes into the body of the msg, the ADD cmd attaches a file.

I'm trying to figure out the sequence of PIPE cmds so that I can replicate the above. Your example above seems close, but trying the following variation isn't working for me:

$ WO="WRITE SYS$OUTPUT"
$ PIPE (WO "Line 1" ; WO "Line 2") |-
(WO "NEW mimefile.out" ;-
WO "INCLUDE SYS$PIPE" ;-
COPY SYS$PIPE SYS$OUTPUT ;-
WO "EXIT"
WO "ADD attachment" ;-
WO "SAVE" |-
MCR MIME
John Gillings
Honored Contributor

Re: Usinge MIME within a PIPE

Jack,

That can be done too... but it's a bit weirder. The NEW/EDIT qualifier accepts a DCL command, which is appended with the filespec of a file to be created. It can be any command, including a call to a procedure, with additional parameters.

So here's a new procedure which calls itself to create the message body.

$ verf='F$VERIFY(F$TRNLNM(F$PARSE(F$ENVIRONMENT("PROCEDURE"),,,"NAME")+"_VERIFY"))
$ self=F$PARSE(";",F$ENVIRONMENT("PROCEDURE"))
$ stat=1
$ IF F$EXTRACT(0,1,p1).EQS."#"
$ THEN
$ target=p1-"#"
$ GOTO 'target'
$ ENDIF
$
$ SomeText="From main"
$ PIPE @'self' #CMDS "mimefile.out" "attach1" "attach2" | MCR MIME
$ stat=$STATUS
$ GOTO FinExit
$
$ CREATE:
$ @'self'/OUTPUT='p2' #CONTENT "''SomeText'"
$ GOTO FinExit
$
$ CONTENT:
$ WRITE SYS$OUTPUT F$TIME()
$ WRITE SYS$OUTPUT "Line2"
$ WRITE SYS$OUTPUT "Line3"
$ WRITE SYS$OUTPUT p2
$ GOTO FinExit
$
$ CMDS:
$ WRITE SYS$OUTPUT "NEW/EDIT=""@''self' #CREATE"" ''p2'"
$ i=3
$ AttachLoop: attach=p'i'
$ IF attach.NES.""
$ THEN
$ WRITE SYS$OUTPUT "ADD ''attach'"
$ i=i+1
$ IF i.LE.8 THEN GOTO AttachLoop
$ ENDIF
$ WRITE SYS$OUTPUT "SAVE"
$ GOTO FinExit
$
$ FinExit:
$ $ EXIT %X10000000.OR.F$INTEGER(stat)+(F$VERIFY(verf).AND.0)


In terms of "efficiency", the reality of the way MIME works is, no matter how you code it, it doesn't avoid temporary files. Done this way they're hidden from you and you don't need to clean them up. Also note my trick of using /OUTPUT to create an output file, rather than OPEN/WRITE and CLOSE - this avoids leaving PPFs open if the procedure exits abnormally.

I've also added some code to illustrate how you can pass parameters into the pipe branches, and also how to turn off verify (necessary now because the /OUTPUT would otherwise include verification if it were enabled).



Note to take this to it's absurd conclusion, I tried this:

$ WO="WRITE SYS$OUTPUT"
$ PIPE (WO "Line 1" ; WO "Line 2") |(in=F$TRNLNM("SYS$PIPE") ; WO "NEW/EDIT=""COPY ",in,""" mimefile.out" ; WO "ADD attachment" ; WO "SAVE") | MCR MIME

In theory it should work, as the 3rd pipe segment can read from the first, BUT the timing of the pipe processes is such that by the time the 3rd segment is executing the COPY command, the first and second segments have exited and the pipe between them has been closed. You can prove the point with a delay at the end of the second segment, but I wouldn't depend on it!

PIPE (WO "Line 1" ; WO "Line 2") | (in=F$TRNLNM("SYS$PIPE") ; WO "NEW/EDIT=""COPY ",in,""" mimefile.out" ; WO "ADD attach
ment" ; WO "SAVE" ; wait 00:00:01) | mcr mime

A crucible of informative mistakes
Steven Schweda
Honored Contributor

Re: Usinge MIME within a PIPE

> I've probably never used MIME to send
> anything (it has enough problems unpacking
> messages), so I know nothing, [...]

Also among the programs which I don't use to
send anything, and so of which I know
nothing, is a VMS-compatible [*] edition of
mpack:

http://antinode.info/dec/sw/mpack.html

[*] The build procedure should work.

On the bright side, munpack has done better
at unpacking a few things than has MIME, but
you're on your own so far as figuring out
what to do with mpack. I assume that you'd
need to enlist the SFF stuff, too, if you
actually wanted anything sent out.
Jack Trachtman
Super Advisor

Re: Usinge MIME within a PIPE

I'm not clear on the use/purpose of the NEW/EDIT="DCL cmd" option. Does this simply spawn a subprocess & execute the DCL? How is this useful - couldn't the DCL simply be run before the MIME program is run?

Anyway, from what I've read, there seems to be no way to pass some text to the MIME program that will wind up in the body of the msg. Correct?
Steven Schweda
Honored Contributor

Re: Usinge MIME within a PIPE

> [...] How is this useful [...]?

It gets its result into MIME without being an
interactive editor (requiring user action for
proper operation)?
John Gillings
Honored Contributor

Re: Usinge MIME within a PIPE

>Anyway, from what I've read, there seems to
>be no way to pass some text to the MIME
>program that will wind up in the body of
>the msg. Correct?

Not correct. It does exactly what you want. The /EDIT= command creates the body of the message. The parameter passed to the command is a file name generated by MIME which it uses as the message body.

The procedure in my last reply gives you a 10 point answer. All the mechanisms you need to do precisely what you requested, using PIPE, 100% of the time.

If you're brave, you could also use the final PIPE command to do it in the least amount of code:

PIPE (WO "Line 1" ; WO "Line 2") | (in=F$TRNLNM("SYS$PIPE") ; WO "NEW/EDIT=""COPY ",in,""" mimefile.out" ; WO "ADD attachment" ; WO "SAVE" ; WAIT 00:00:01) | MCR MIME

The body of your message is
Line 1
Line 2

BUT you're depending on the 1 second delay in the second pipe stage to be long enough for the third pipe stage to kick off and start reading from the first stage. It's probably a 99.99% solution, but some day on a very busy system it will fail (I experimented with other mechanisms to synchronise the processes, but couldn't find one).
A crucible of informative mistakes
John Gillings
Honored Contributor

Re: Usinge MIME within a PIPE

Yet another way - as a one liner:

PIPE (-
WO "NEW/EDIT=""PIPE (WO """"Body1"""" ; WO """"Body2"""")|COPY SYS$PIPE"" mimefile.out" ; WO "ADD attachment" ; WO "SA
VE") | MCR MIME

Be careful with quotes!
A crucible of informative mistakes
Jack Trachtman
Super Advisor

Re: Usinge MIME within a PIPE

Sorry John, I'm just not groking how to use the /EDIT=dcl function. The MIME help text example is not clear to me.

So lets say I have file msg.txt that I want MIME to put into the msg body part of some file. along w/an attached file. What would I use:

$ MIME
MIME> NEW/EDIT=???
MIME> ADD attachement
MIME> SAVE
MIME> EXIT
John Gillings
Honored Contributor
Solution

Re: Usinge MIME within a PIPE

Jack,

> I'm just not groking how to use >the /EDIT=dcl function

Yes, MIME has chosen a rather odd way to do the message body. I can see why you might have trouble groking. And I agree, the help text isn't very helpful.

Perhaps this will help...

MIME> NEW myfile

creates "myfile" with MIME headers, yes? The default is /EDIT which invokes a default interactive text editor to create the body text. However, the /EDIT qualifier is more general than that, it can be any command which creates a file. If you type:

MIME> NEW/EDIT="MYCOMMAND" myfile

the MIME command executes your command (presumably with SPAWN), appended with the name of a temporary file. Something like:

$ MYCOMMAND SYS$SCRATCH:MIME$656F_MSG.TXT

Note that the file doesn't exist when the command is invoked. If it exists when the command completes, it will be inserted into the MIME file as the message body. It appears this is the only mechanism for specifying the message body.

So you can see how the default action is really just /EDIT="EDIT/EDT", resulting in:

$ EDIT/EDT SYS$SCRATCH:MIME$656F_MSG.TXT

>So lets say I have file msg.txt that I want
>MIME to put into the msg body

The simplest possibility I can think of is:

MIME> NEW/EDIT="COPY MSG.TXT" mimefile.out

That would be appended with the temp file name and become:

$ COPY MSG.TXT SYS$SCRATCH:MIME$656F_MSG.TXT

MIME would then include the contents of the file into the output file, and delete the temporary file.

I too find this rather odd, it may have made more sense to have /BODY=file, but I suppose the utility was designed to be interactive. It has a kind of "swiss army knife" generality appeal, but it's also a bit klunky.

The variations I've posted are just different ways of feeding some text into some command to generate a file, specified as the last token in the command.

I used two command procedure to investigate what /EDIT was doing:

TEST.COM
$ @TEST1 /OUTPUT=TEST.OUT "''p1'" "''p2'" "''p3'" "''p4'" "''p5'" "''p6'" "''p7'" "''p8'"
$ EXIT

TEST1.COM
$ SHOW SYM p%
$ DIR 'p1'
$ EXIT 1

execute a command:

MIME> NEW/EDIT="@TEST" newfile

and look in TEST.OUT.

(BTW, I believe it's possible to reopen a thread in order to award points... ;-)
A crucible of informative mistakes
Jack Trachtman
Super Advisor

Re: Usinge MIME within a PIPE

Excellent John! Not only have you patiently taken the time to explain the details I needed to be able to do exactly what I want, but you've educated me in some fine points!

Last question: how do I reopen this thread so I can add points?
Jon Pinkley
Honored Contributor

Re: Usinge MIME within a PIPE

At the top of a closed thread, the author (you) should see a "reopen thread" button, to the left of the "notify","reply" etc. buttons.

Jon
it depends
Jack Trachtman
Super Advisor

Re: Usinge MIME within a PIPE

Thanks again