I often have the opportunity to work on Unix systems, and one of the things that impresses me about their shell scripts is how easy it is to send e-mail from them. They can just format the e-mail message in the script and send it to a program named Sendmail on their system, and presto! The message is sent.
Because I miss that capability on i5/OS, I decided to write an RPG program that I can invoke from QShell to accomplish the same thing. With my RPG utility, I can write QShell scripts that work exactly like the Unix ones.
On Unix systems, a "shell" is a command-line environment. When you log on, you're placed at a shell. This is where you type commands. The shell interprets the command you type and runs the appropriate program(s) that implement the code that runs behind the command.
A shell script is a text file that contains a list of the commands to execute. It's analogous to a CL program on i5/OS, or to a batch file on Windows.
Both the QShell and PASE environment of i5/OS have shells and can run shell scripts.
One feature that makes a shell script so useful is something called a "here document," which lets a script treat a group of lines (inside the script itself) as a file that can be directed to the standard input of a program.
For example, here's a simple QShell script that writes the first two paragraphs of the Gettysburg Address. This data is written directly to QShell's cat utility, which in turn, prints the text on the screen:
cat << end_of_data Four score and seven years ago, our fathers brought forth on this continent a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal. Now we are engaged in a great civil war, testing whether that nation, or any nation, so conceived and so dedicated, can long endure. We are met on a great battlefield of that war. We have come to dedicate a portion of that field, as a final resting place for those who here gave their lives that that nation might live. It is altogether fitting and proper that we should do this. end_of_data
The << characters tell QShell that you want to read a "here document." The << characters are followed by a word (in this example, "end_of_data") that designates the end of the here document. Everything after that is considered part of the document and gets written to the standard input of the cat utility.
The cat utility prints its standard input to the screen. Therefore, if you run the preceding screen, it prints the first two paragraphs of the Gettysburg Address on your screen.
If you'd like to try it, do the following:
Save the preceding code to a text file in your IFS. On my system, I called it /tmp/gettysburg.
Start QShell by typing STRQSH
Type chmod +x /tmp/gettysburg to provide the appropriate authority to run the file as a script.
Type /tmp/gettysburg to run the script.
On a Unix system, using a here document to send an e-mail message is easy. You simply format your here document according to the rules of an e-mail message, and you tell the shell to write it to the Sendmail program. For example:
#!/bin/sh /usr/sbin/sendmail -o -t << end_of_msg From: Scott Klement <sklement@systeminetwork.com> To: Abe Lincoln <lincoln@whitehouse.gov> Date: Thu, 9 Nov 2007 15:31:00 -0600 Subject: Honest Abe Dear Abe: This is a demonstration of an e-mail message. At this point in the message, I put whatever I want to say to you. end_of_msg
When this runs, the Sendmail program is invoked. Sendmail reads its standard input (which is the here document) and sends the e-mail. It's very simple and elegant, isn't it?
The problem is that the Sendmail program is more than just a tool for sending messages. It's an entire SMTP server, and it requires a significant learning curve to set up and run properly. Most i5/OS shops already use the SMTP server included with i5/OS, and they aren't interested in running Sendmail as well.
My solution was to write an RPG program that reads the e-mail message from its standard input, just as the Sendmail program would do. The RPG program then saves the message to a stream file in the IFS and calls the QtmmSendMail() API to send the message via i5/OS's native SMTP server. This way, you don't need to try running Sendmail on i5/OS. You can just use the i5/OS SMTP server like you always have.
Here's a sample QShell script that uses my utility to send mail:
/qsys.lib/scott.lib/mailsend.pgm << end_of_msg From: Scott Klement <sklement@systeminetwork.com> To: Abe Lincoln <lincoln@whitehouse.gov> Date: Thu, 9 Nov 2007 15:31:00 -0600 Subject: Honest Abe Dear Abe: This is a demonstration of an e-mail message. At this point in the message, I put whatever I want to say to you. end_of_msg
In this example, my RPG e-mail tool is a program object named MAILSEND and it's located in the SCOTT library. The here document is directed to its standard input, just as I did with the cat and Sendmail tools earlier.
Of course, in a real application you probably wouldn't want to hard-code the date (as I did in the preceding example). So I also wrote a utility called MAILDATE, which retrieves the current date from the system so that it can be included in a QShell script.
/qsys.lib/scott.lib/mailsend.pgm << end_of_msg From: Scott Klement <sklement@systeminetwork.com> To: Abe Lincoln <lincoln@whitehouse.gov> Date: $(/qsys.lib/scott.lib/maildate.pgm) Subject: Honest Abe Dear Abe: This is a demonstration of an e-mail message. At this point in the message, I put whatever I want to say to you. end_of_msg
In the preceding example, the MAILDATE program in the SCOTT library is called by QShell. Anything it writes to standard output (in this case, the e-mail timestamp) is inserted after the Date: keyword in the e-mail message.
The MAILSEND program works by scanning the e-mail document for the To: and From: headers that denote who the message is for and who it's from, respectively. It then uses this information to invoke the QtmmSendMail() API.
At this time, the MAILSEND program is limited to sending to only one recipient at a time. If you list more than one recipient in your e-mail message, only the first one is used. Others are ignored.
Also, there's currently no easy way to send attachments with the MAILSEND utility.
If you find these techniques useful, and you'd like me to expand my utilities to provide support for multiple recipients and/or attachments, please let me know by sending an e-mail to tips@scottklement.com. If I receive enough responses from readers, I will extend my tools in a future article.
You can download the MAILSEND and MAILDATE utilities from the following link:
http://www.pentontech.com/IBMContent/Documents/article/55313_283_MailSend.zip
For more information about the format of e-mail messages, and how to send them from within an RPG program, please read the following articles on SystemiNetwork.com:
For more information about QShell and PASE programming, please read the following articles:
Writing Your Own QShell Utilities (February 11, 2007, article ID 54053)
(ProVIP) What QShell and PASE Can Do for You (April 2007, article ID 20850)