IBM i Modernization - The User Interface
(Part 17)
This article discusses the idea of sending email from web browsers. Please click on the following screen shot to try it.
Use Cases
Email is of course a basic necessity for modern business. Large and small services providers offer robust web-based clients - some of which have become hugely popular.
I believe that IBM i would be a great platform for hosting email as a service for thousands of concurrent users similar to Google and Yahoo Mail. However, for purposes of this discussion, let's keep the requirements small.
Email may simply be an appendage to something like a help-desk application that provides a form for submitting requests for support. Email messages and attachments might be forwarded to technicians, for example.
Just The Basics
The form featured in this article is designed for browsers that have implemented the HTML5 specification. The application does the following:
- Prompts users to enter their own email address and message text.
- The Form's values are sent to an ILE RPG program named IUI105.
- The IUI105 program sends an email message to a recipients list, which is maintained in an IBM i data area. It sends a "thank you" email to the originator of the request. It returns a confirmation to the browser.
I considered adding attachments to email messages by using a file-upload utility similar to the one shown in Part 16. I finally chose to keep the scope of the application smaller so that it might be more digestible.
Email Account Inputs
HTML 5 provides for an input element of type "email" for entering email addresses:
Email inputs invoke some built-in behaviors in HTML5 browsers. Smart phones may show @ and .com keys on their keypads, for example.
Pattern="regular expression" provides basic email-account validation against a regular expression. You can find recommendations for regular expressions via search engine results.
The Form's JavaScript
The send() function is invoked when the form is submitted (via button click or the "enter" key).
function send() {
reqPost('/rdcaller/send.shtml?rwappid=iui105' ,fm.pd());
return false;
}
High-level explanation of send():
- The form's data elements are posted to the server (program IUI105 is called to process it).
- returning "false" overrides the default form submit (reqPost() uses AJAX instead).
The us() function is invoked by the response from the IUI105 program:
function us(rt) {
fm.sa('msg','value','');
fm.sf('addr');
um.innerHTML = rt;
}
High-level explanation of us():
- The IUI105 program returns a "thanks" message.
- The value of the "msg" input element is set to an empty string.
- The focus is set to the "addr" input element.
Program IUI105
An RPG program named IUI105 responds to the "send" request. The code is as follows:
//----------------------------------------------------------------- // procedure prototypes //----------------------------------------------------------------- /copy *libl/qrpglesrc,rdstrapi#1 /copy *libl/qrpglesrc,rdemlapi#1 /copy *libl/qrpglesrc,rdwtnapi#1 //----------------------------------------------------------------- // module level data //----------------------------------------------------------------- d rw e ds extname(rwpgmc) qualified d s1 s * inz(*null) d recipients s 256a dtaara(recipients) d xeml e ds extname(xeml100p) import d qualified d xemlmsg s 32765a varying import d crlf s 2a inz(x'0D25') d addr s 256a varying //----------------------------------------------------------------- // program entry //----------------------------------------------------------------- c *entry plist c parm rw /free //----------------------------------------------------------------- // set reference to UI template //----------------------------------------------------------------- if s1 <> *null; wtnSetInst(s1); endif; //----------------------------------------------------------------- // branch to subroutines based on requested actions //----------------------------------------------------------------- select; when rw.action = 'INIT'; exsr do_init; when rw.action = 'SEND'; exsr do_send; endsl; return; //----------------------------------------------------------------- // initialization //----------------------------------------------------------------- begsr do_init; s1 = wtnOpen('IUI105'); in recipients; clear xeml; xeml.subject = 'IBM i UI Modernization - (Part 17)'; xeml.sender = 'noreply@rd.radile.com'; xeml.replyto = xeml.sender; endsr; //----------------------------------------------------------------- // send email to data-area recipients //----------------------------------------------------------------- begsr do_send; addr = %trimr(wtnFldGet('addr')); xemlmsg = wtnFldGet('msg'); xemlmsg = strReplace(xemlmsg:'\n':crlf); xeml.recipients = %trimr(recipients); emlSend(); //----------------------------------------------------------------- // send "thanks" email to originator //----------------------------------------------------------------- xeml.message = ' '; xemlmsg = 'Thanks for your email @ ' + %char(%date():*usa) + ' ' + %char(%time():*hms) + '.'; xeml.recipients = addr; if addr <> ''; emlSend(); endif; //----------------------------------------------------------------- // send "thanks" to browser //----------------------------------------------------------------- wtnRecSet('US'); wtnFldSet('um':xemlmsg); wtnRecWrt('US'); endsr; /end-free
High-level explanation of program IUI105:
Program IUI105 binds to a service program named RDEMLAPI, which implements an high-level email interface by exporting a procedure named emlSend(), an external data structure named XEML, and a variable-length string named XEMLMSG (in which you can store email message content).
Any ILE program or service program can bind to RDEMLAPI, assign values to XEMLMSG and XEML sub-fields, and call emlSend() to send email messages.
We should review the layout of the XEML data structure that is externally described in file XEML100P:
A UNIQUE A R XEML100R TEXT('Email Requests') A SENDER 128A COLHDG('Sender Email Address') A VARLEN A MESSAGE 128A COLHDG('Message File') A VARLEN A SUBJECT 128A COLHDG('Subject') A VARLEN A RECIPIENTS 7936A COLHDG('Recipients List') A VARLEN A CARBONS 7936A COLHDG('Carbon Copy List') A VARLEN A BLINDS 7936A COLHDG('Blind Copy List') A VARLEN A ATTACHS 7936A COLHDG('Attachments List') A VARLEN A REPLYTO 128A COLHDG('Reply To Address') A VARLEN A ORG 64A COLHDG('Organization') A VARLEN A CTYPE 4A COLHDG('Content Type') A ERRTEXT 128A COLHDG('Error Message') A VARLEN A ERRFLAG 1A COLHDG('Error Flag') A KEEP 1A COLHDG('Keep Message Flag') A TS Z COLHDG('Timestamp') A ID 10S 0 COLHDG('ID') A K ID
- SENDER - Assign the sender's email address.
- MESSAGE - Optionally assign an IFS stream file name to hold the email, otherwise a temporary IFS file is created.
- SUBJECT - Assign a string that appears in the email "subject" line.
- RECIPIENTS - Assign a comma separated list of recipient email addresses.
- CARBONS - Assign a comma separated list of carbon-copy recipients.
- BLINDS - Assign a comma separated list of blind-carbon-copy recipients.
- ATTACHS - Assign a comma separated list of IFS stream file attachments.
- REPLYTO - Optionally assign an email address to reply to (if different from SENDER).
- ORG - Optionally assign an "organization" that will appear in email headers.
- CTYPE - Optionally assign "HTML" if the content type is HTML-formatted text (otherwise plain/text is used).
- ERRTEXT - Contains any error message returned after calling emlSend().
- ERRFLG - Contains "Y" if emlSend() returns an error.
- KEEP - Assign "Y" if you want to keep the MESSAGE stream file (the default is to delete it after the email is sent).
- TS & ID - Timestamp and a unique key are assigned to each email sent.
You can make repeated calls to emlSend() - just altering the xeml.blinds list - when sending bulk email to many recipients. If you assign a new value to the XEMLMSG string, you need to assign a new value to the MESSAGE (IFS file) to send a different email message.
Wrapping Up
There are quite a few use cases for using web browsers and IBM i programs to send email to recipients. Hopefully this article stirs some consideration.