by John Staub, President, Staub & Associates, Inc.
FUNCky is an excellent set of third-party tools for dBASE. It has so many different and widely varied routines that can be easily included in a dBL app that we consider FUNCky a necessary part of our developer tool set. We use it for FTP processes, sending single and bulk e-mails, testing for the existence and/or availability of certain drives, provide system information to users, etc., all from within dBL applications.
What is required?
Of course, you'll need a registered copy of FUNCky, available from the dBASE on-line store at http://www.dBase.com. If you are using any of the FUNCky routines in a client's application, you will need to install FUNCky.dll and FUNCky.TLB on their computers and/or server(s), and register FUNCky.dll on each machine. These install and registration processes can be included in your installation program, and are especially easy to do using Inno (our preferred install package) or similar packages that allow you to run automated processes during the install.
Our User's Environment
In this article, we will use a fairly complex user environment as an example. This particular client has a dBL app that we built and which runs across a LAN and on a Terminal Server, serving 9 sales locations in 3 different countries. The application is installed on each workstation on the LAN, and we configured the Terminal Server environment to accommodate multiple users. They also have a separate e-mail server as part of the domain.
During the building of this application, one requirement was to be able to send e-mails to particular clients, and to be able to send bulk e-mails to a wide variety of clients. Each client record contains two fields for e-mail addresses, and the application provides for filtering client records in a multitude of methods. Additionally, we can send an e-mail to either or both e-mail addresses in the client record. Each sales agent has the ability to filter records based upon whether the client is a sold customer, a prospective customer, the make/model of car they are interested in, etc. This provides each sales agent the ability to target their e-mails, especially when sending bulk e-mails. Additionally, following the successful sending of an e-mail, a client follow-up record is created, documenting the contact with each client.
In the first use of the bulk e-mail send process, the company sent out announcements for the unveiling of a new series automobile. They were hosting a coming out party at each of their sales locations. While I'm not sure the bulk e-mail played a major role in the overwhelming success of the event, it provided them the means to send an announcement to each prospective customer. The attendance at this event was significantly greater than at previous events and advertising costs for the event were similarly reduced.
FUNCky SMTP plays a major role in our ability to send e-mails from within our application.
The E-mail Form
The forms we use
are pretty simple and straight-forward. We include the name
of the client, their e-mail address, a CC and BCC field, text,
and the ability to add an attachment. Most of the information
for the form is gathered before we ever open the form from values
in entryfields on the currently open form. We call the form
in the following manner:
if not empty(form.cust_entryfield12.value) //first e-mail address field on the client form
set procedure to one_email_send.wfm additive // one of our e-mail forms
oEmail = new one_email_sendform()
oEmail.EmailAddress = ' '
// check which email address to use if two e-mail addresses exist
if not empty(form.eCust_Address1.value) AND ;
not empty(form.eCust_Address2.value) // both e-mail address fields on the calling form
set procedure to whichemailaddress.wfm additive
oWhich = new which_email_addressform()
oWhich.MDI = false
oWhich.first_email = false
oWhich.second_email = false
oWhich.both_email = false
oWhich.first_email_address = form.eCust_Address1.value
oWhich.second_email_address = form.eCust_Address2.value
// when the form for determining which e-mail address to use opens, it displays
// both e-mail addresses and pushbuttons for First, Second or Both e-mail addresses
oEmail.EmailAddress = trim(form.eCust_Address1.value) // the first e-mail address on the form
oEmail.EmailAddress = trim(form.eCust_Address2.value) // the second e-mail address on the form
oEmail.EmailAddress = trim(form.eCust_Address1.value) + ;
"; " + trim(form.eCust_Address2.value) // both e-mail addresses separated by a semi-colon
endif // which e-mail address to use
// since we use Boolean values from the which_email_address form, closeout
// the form now as they are no longer needed
oWhich = null
close procedure which_email_address.wfm
else // only one e-mail address exists
oEmail.EmailAddress = trim(form.eCust_Address1.value) // first e-mail address on the calling form
endif // not empty both e-mail addresses
oEmail.ClientNumber = form.eClient_Number.value // clientnumber
oEmail.MDI = false
oEmail = null
close procedure one_email_send.wfm
else // no e-mail address is on record
MSGBOX("There is not a valid e-mail address for this record","No valid e-mail address")
Instantiating and opening the form is a pretty simple and straight-forward process. We check to see if there is an e-mail address for this client record, then we give the user the option of using the first, second or both addresses if two addresses exist. The ClientNumber is a unique record identifier (AutoIncrement field) and is used in the actual e-mail form so we can create a follow-up record for this client if the e-mail is sent. One thing you may want to note is how we use variables from two different forms to handle specific information and to determine which e-mail address to use. If only one e-mail address is on record, we just grab that value from the client form's entryfield and use it. If no e-mail address is in this client's record, we notify the user and close out the process
In the on_Open() event of the e-mail form, we insert values into several fields on the e-mail form. For a variety of reasons, we use disabled entryfields on the actual e-mail form to store the To, From and BCC addresses. Additionally, we create a form.variable to hold the information for any attachments a user may want to include with the line form.attachments = ' '
If the users want to include
an attachment, when they click the Attach button,
the following code is run:
form.attachments = iif(empty(form.attachments), null, form.attachments + ", ") ;
form.editor2.enabled = true
form.editor2.value = ' '
form.editor2.value = form.attachments
The real FUNCky work starts
when the user clicks the Send button:
set procedure to Funcky.cc additive
Smtp = New FUNCkySmtp()
Smtp.Server = "mymail_server.com" // IP addresses can also be used
Smtp.FromName = form.eAgent_Name.value
Smtp.FromAddress = form.eFrom_Address.value
Smtp.Subject = form.eSubject.value
Smtp.ToName = form.eToName.value
Smtp.ToAddress = form.eTo_Address.value
Smtp.BCC = form.eBCC.value
Smtp.Message = form.editor_message.value
if not empty(form.attachments)
Smtp.Attachments = form.attachments
if( Smtp.Send(True)) // e-mail sent successfully
// call the routine to create the client followup record
else // first attempt failed using the mail server IP address
Smtp.Server = "myothermailserver.com" // perhaps use the internal LAN address of the mail server
// call the routine to create the followup record
MSGBOX("e-mail Send Failed...Status Message is " + Smtp.StatusMessage," ")
MSGBOX("Error is " + Smtp.Error," ")
MSGBOX("Error Message is " + Smtp.ErrorMessage)
endif // second send attempt
endif // first send attempt
close procedure Funcky.cc
form.close() // close the form and get back to business
In the code example above, we populate several properties of the FUNCky SMTP methods, i.e., Server, the various addresses, and the text message, and we identify any attachments the user may want to include. Additionally, we try sending the e-mail twice, using two different mail server addresses. Note that when identifying the SMTP server, you can use IP addresses or the actual server name. If your users are on a LAN, you can use the local IP address of the mail server. If the send is successful, we notify the user, and call the Class to create the client followup record. If both sends fail, we notify the users and provide them the error codes and messages. Fortunately we are blessed with fairly competent users and if they encounter an error message like the above, they write them down and notify our tech support so we can troubleshoot the problem.
If you were in an environment where the IP addresses of the mail servers change, you could store the values for the servers in a configuration table and just grab the values from there.
As mentioned earlier,
we also use FUNCky and dBASE to handle sending bulk e-mail.
First we loop through the client records, copying each e-mail
address and client name to a temporary table. Then we open
a form used for bulk e-mail which allows the user to type in the
text message. When the user clicks the send button, the
following code is run:
// now setup the necessary loop
and functions to complete the
d = new database("PCSLOCAL")
// BDE Alias used for
local, temporary tables
db = new database("PCS") // BDE Alias used for networked tables
r = new query()
s = new query()
t = new query()
// now validate the names and
e-mail addresses to
// now get ready to send out
While much of the above code is specific to our form for sending bulk e-mail, I believe it demonstrates an approach that you can easily adapt to your circumstances.
This particular client also sends a variety of form e-mails to customers throughout the process of building and delivering the customers' cars. These e-mails are built and sent using a .cc file we developed specifically for this purpose. While we use the same .cfm e-mail form as in the above examples, the populating of the various fields, and especially the formatting the e-mail text is handled through our .cc file.
Sending e-mails using either of the above examples is extremely fast.
FUNCky provides a wide
variety of tools for the dBASE user. The help file is complete
and includes well-documented examples for a variety of programming
languages. Much of the above code was derived
(okay, borrowed) directly from the FUNCky examples.
Technical support is excellent and available from the FUNCky web
site at http://www.FUNCky.com. There is a new FUNCky demo for
dBASE available at (watch for word wrap)
We use FUNCky for a variety
of purposes and have found it to be very easy to integrate into
a dBL app. Perhaps it's time for you to get FUNCky.