Tuesday 24 February 2015

snLibrary - Emailing & SMS (v6.0 - 14th Dec 2008)

snLibrary :- Emailing


History:
It was during 2007-08 that we faced lot of network issues at our old data-centre.  Those days, we had a mailing software from IBM called Lotus-Domino.  Domino was a pretty simple and sturdy mailing solution on Linux platform.  However, frequent network failures (we had very old 3-Com switches at that time), with the advent of new web-applications that demanded emailing from within them, put heavy load on the SMTP (Simple Mail Transfer Protocol) server of Lotus Domino and it was found that many a time, emails did not get transferred.  The emails sent from programs did not get any response either causing many programs to go into 'hang' state.

Enough attempts were made to flag the issue for resolution, but in vain.  The network team was also helpless because, hardware procurement and network re-cabling was very time consuming - and not until 2010-11 or so could we actually procure good quality switches and complete the massive re-cabling exercise.

The issue turned severe with the launch of eCFS (electronic Customer Feedback System) and some solution had to be found.  Given the situation of crisis, was born the snSendMail class of snLibrary.  In this blog we will discuss the same.

I suggested (and got a small award as well !!)  that we could do a Buffered Multi-threaded Ensuring Email Dispatch system, that would initially store/stage the requested email in a database table and thereafter frequently try sending them in a scheduled manner to the Lotus Domino's-SMTP server.  This was a great success at that time.  The snSendEMail / snSendMail classes were included in the snLibrary (on 14-Dec-2008 in version 6.0).


Send an Email

Implementation:-
I will therefore explain the implementation methodology.  It should be understood that the methods have the feature for sending without buffering.  In case where there is an attachment, it actually does only direct sending without buffering using the database table.

Create a file (snMailmyApp.ini) inside the mail folder of snConfigFile folder with the following entries.
File:- c:/snConfig/mail/snMailmyApp.ini
mail intranet prefix=http://webapp.indianoil.co.in/myapp/
mail internet prefix=http://webapp.indianoil.co.in/myapp/

#mail host=10.146.64.200
#mail port=25
#mailer=smtpsend
#mail user=hohrd@indianoil.co.in
##mail pass=
#Verbose=true
#SMTP Auth=false
#Debug=true
#SSL=false

#mail host=smtp.gmail.com
#mail port=465
#mailer=smtpsend
#mail from=hohrd@indianoil.co.in
##mail from=indianoil.mktg.ho@gmail.com
#mail user=indianoil.mktg.ho
#mail pass=
#Verbose=true
#SMTP Auth=true
#Debug=true
#SSL=true

#mail host=10.146.64.80
#mail port=25
#mailer=smtpsend
#mail user=hohrd@indianoil.co.in
#mail pass=
#Verbose=true
#SMTP Auth=false
#Debug=true
#SSL=false

#mail host=10.146.64.173
mail port=25
mailer=smtpsend
#mail user=hohrd@indianoil.in
mail pass=
Verbose=true
SMTP Auth=false
Debug=true
SSL=false

mail from=e_suggestion@indianoil.in

mail user=hohrd@indianoil.co.in

mail host=mkhoexht.ds.indianoil.in

Send Mail Via WebService=false

Send Mail Via Staging Database=false

#Staging Database Insert SQL=insert into SMTPStagingDB.newEmails (created_by, mail_host, mailer, user, passwd,debug, verbose, auth_required, use_SSL, mail_from, mail_to, mail_cc, mail_bcc, mail_subject, mail_text) values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)

Staging Database Insert SQL=insert into newEmails (CREATED_BY, MAIL_HOST, MAILER, USERID, PASSWD, DEBUG_ON, VERBOSE_ON, AUTH_REQUIRED, USE_SSL, MAIL_FROM, MAIL_REPLY_TO, MAIL_TO, MAIL_CC, MAIL_BCC, MAIL_SUBJECT, MAIL_TEXT, YYYYMMDD, CREATED_ON, UPDATE_FLAG) VALUES (?, ?, ?, ?, ?,   ?, ?, ?, ?, ?,   ?, ?, ?  , ?, ?, ?, to_char(SYSDATE,'YYYYMMDD'), SYSDATE, 'A')

For the purpose of connecting to the database, we need to provide the Connection parameters in an external file.  We can give this in the following manner.
File:- c:/snConfig/ConnEmailDB.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<entry key="Name">EmailDB</entry>
<entry key="DataBase Type">Oracle</entry>
<entry key="Driver">oracle.jdbc.driver.OracleDriver</entry>
<entry key="validation">SELECT 1 from dual</entry>

<entry key="Max Active Connections">10</entry>
<entry key="Max Idle Connections">5</entry>
<entry key="Min Idle Milliseconds for Statement Eviction">0</entry>
<entry key="Max Wait Milliseconds until New Connection">0</entry>
<entry key="Max Active Statements">0</entry>
<entry key="Max Idle Statements">0</entry>

<entry key="Load Database Pool on Startup">true</entry>

<entry key="login">email</entry>
<entry key="pass">email_pswd</entry>
<entry key="JDBCurl">jdbc:oracle:thin:@10.146.64.73:1521:tranDB</entry>
</properties>

Now insert the following line in the snConfigFile of the application as given below.
File:- c:/snConfig/snConfigMyApplication.ini
MailConfigFileName=c:/snConfig/mail/snMailmyApp.ini
DataBase Connection Properties XML File Name for Emailing=c:/snConfig/mail/ConnEmailDB.xml


How can I send an Email?
Having made these updates in the respective files, we will now see how this can be implemented in a Java program.  Firstly we will assume that we have set Buffered emailing feature to false. (ie. we will assume that we have set the 'Send Mail Via Staging Database' option to false.
A sample java code for emailing is given below:-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import config.log.LogErrorWriter;
import utils.snSendEMail;

public class myClassA {
// ..... some code of the program....

   //Logger logger = LoggerFactory.getLogger(this.getServletName() + ".class");
   Logger logger = LoggerFactory.getLogger(myClassA.class);
   LogErrorWriter lew = new LogErrorWriter(logger);

   snSendEMail snM = new snSendEMail();
   
   // ...
   // Define the variables and set appropriate values .......
   // ...
   
   if (lew.writeEmailInfo(snM.snSendEMail(send_to, "","", emailSubj, emailStr),
                  logger, send_to, emailSubj, emailStr)) {
        emailedToList += " [" + send_to + "] ";
   }
   // ....
   logger.info("Emails have been sent to : {}", emailedToList); 
   // ....

//  some part of the program
}

The above codelet would automatically take care of sending the email based on whether or not the configuration setting is for Buffered-Multi-threaded Email Dispatch or through direct SMTP call. Hence the developer need not be worried about how it would get implemented in the Production System - whether it would be through the database, direct SMTP or through web-services calls - Rest Assured, that it works well!!

You may also wish to explore other methods of the snSendEMail class wherein you could specify the from id, attach files, send the message in an HTML / Text format (- text is default) etc.

It may also be noted that it is possible to pass a Config File as part of parameterized constructor
   snSendEMail snM = new snSendEMail(configFileName);


Send an SMS

How can I send an SMS?
Now that you have seen how to send Emails, Sending SMS is just as easy and on very similar lines. The following code is for sending SMS via DatabaseTables.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import config.log.LogErrorWriter;
import utils.snSendSMS;

// ...
// Some part of the code runs here ....
// ...
                  Logger logger = LoggerFactory.getLogger(this.getServletName() + ".class");
                  LogErrorWriter lew = new LogErrorWriter(logger);

                  snSendSMS snSMS = new snSendSMS();

                 //SMSObject smsObj = new SMSObject();
                 //snSMS.setInsertSQL(smsObj.getInsertSQL());
                 //snSMS.setSMSData(smsObj.getColumnObjectValues(sms_mobile, smsStr, ""));
                 
                 Object[] smsObject = {sms_mobile, smsStr, createdBy};
                 snSMS.setSMSData(smsObject);
                 lew.writeSMSInfo((0 < snSMS.sendSMS("SMS")), logger, sms_mobile, smsStr, "");

// ...
// Some part of the code runs here ....
// ...

File:- c:/snConfig/snConfigMyApplication.ini
SMSConfigFileName=c:/snConfig/sms/snSMSConfig.ini
DataBase Connection Properties XML File Name-SMS=c:/snConfig/ConnSMS.xml

File:-c:/snConfig/sms/snSMSConfig.ini
Send SMS Via WebService=false
SMS Insert SQL=insert into SMS_DETAILS VALUES (?, ?, ?, SYSDATE)


There is also code for sending SMS via Web-service (which has been tested and bug fixed as of version 26.0 dtd. 19.01.2016).  The list of configuration parameters for the same is given below:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 
import utils.snSendSMS;

// ...
// Some part of the code runs here ....
// ...
                  Logger logger = LoggerFactory.getLogger(this.getServletName() + ".class"); 

                  snSendSMS snSMS = new snSendSMS(); 

//... sms_mobileNo_list is a comma separated (or as defined by the 
//             parameter "SMS MobileNo delimiter") list of Mobile Nos. 
//             Eg:- 9425013000,9876543210,9988776655
//... smsText is text limited to allowable characters of a text message thru SMS.

                 Object[] smsObject = {sms_mobileNo_list, smsText};
                 snSMS.setSMSData(smsObject);
                 int countOfSMSsent = snSMS.sendSMS("SMS");   
// May use snSMS.sendSMS(); if Staging DB is not being used or planned in future. 
// Only .ini file change would then be required.  

                  if (countOfSMSsent > 0) {
                      log.info("SMS to : {} against request id : {} sent. Count of SMSs = {}", new Object[]{smsObject[0], "" + reqId, "" + countOfSMSSent});
                  }

// ...
// Some part of the code runs here ....
// ...

File:- c:/snConfig/sms/snSMSConfig.ini

#--- If Send SMS Via WebService is true, then the application should have included 
# a Web-Service Client in the project itself.
# This can be done using the WSDL published for this purpose. 
# Contact your system administrator to get the correct Web-Service WSDL URL 
# Eg:- http://webapp.indianoil.co.in/IOCWebService/SMSAsService?wsdl 
  If no WebService has been included, the use of method would use SOAP over HTTP if the parameters are set to true in both cases. 
Send SMS Via WebService=true

Mobile-Number Length=10 
#User Id=paribhavam 
#Password=xxxxxx 
#Dept Id=19 
#Send Message as Flash=true 
#Message Type=MsgType 
#Message Validity in seconds=18600 
#Sender=IOCL 

Send using SOAP HTTP Template=true 
SMS SOAP Template File=c:/snConfig/sms/snSMSviaHTTP.xml 
SMS Gateway URL=http://sandesh.indianoil.co.in:80/IOCSMSGateway/SMSGateway 
SMS SMS Content-Type=text/xml; charset=utf-8

#SMS Object Mobile No. ordinal=0 
#SMS Object Message Text ordinal=1 
#SMS Object User Id ordinal=-1 
#SMS Object Password ordinal=-1 
#SMS Object Dept Id ordinal=-1 
#SMS Object Send Message as Flash ordinal=-1 
#SMS Object Message Type ordinal=-1 
#SMS Object Message Validity in seconds ordinal=-1 
#SMS Object Sender ordinal=-1 


#SMS Insert SQL SMS Insert SQL=insert into SMS_DETAILS VALUES (?, ?, ?, SYSDATE) 

Send SMS Copy to=9977455596,9977455596,9425013000
SMS via HTTP MobileNo Tag=<mobile_no></mobile_no>
SMS via HTTP SMS-Content Tag=<sms_content></sms_content>
SMS via HTTP Response Tag=<return>S</return>
SMS MobileNo delimiter=,

Split and send SMS=true


Sample SOAP Template file is given below.
File:- c:/snConfig/sms/snSMSviaHTTP.xml
<?xml version="1.0" encoding="utf-8" ?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ioc="http://ioc/">
  <soapenv:Header/>
  <soapenv:Body>
  <ioc:OutGoingSMS>
    <mobile_no></mobile_no>
    <sms_content></sms_content>
    <sms_type>
ENG</sms_type>
    <userID>
SMSuser</userID>
    <password>
SMSpswd</password>
  </ioc:OutGoingSMS>
  </soapenv:Body>
</soapenv:Envelope>

Change the sms_type, userId, password etc. accordingly (including their values) as required.  The mobile_no, sms_content fields would be appropriately populated before sending. Note that there should not be any space between the open and the end tags of  mobile_no and sms_content.

(Note:- This code has been tested successfully as of Version 26.0 dtd. 20.01.2016)




1 comment: