Author: Michael Elfial
Everybody involved in the WEB programming knows that WEB forms can be submitted through e-mail. But in most cases this method is not very useful. Is this the truth?
I'll begin with the basics. If the ACTION attribute of the form contains address which uses mailto: protocol the browser uses the mail settings of the default e-mail program on the user's machine and also uses that client to do the real work. The browser behavior is very different depending on the value of the METHOD attribute. If GET is used Browser does almost nothing - it just passes the the form fields URL encoded to the mail client and everything else depends on it. Usually the mail client uses some of the fields only - Subject to fill the message subject, Body to fill the body. URL encoded body is not good for human reading, also not all the fields are sent ... which makes no sense at all.
The situation is different if POST is used for the METHOD value. It does something very useful - all the form fields are URL encoded and attached to the message - i.e.all the form data is sent as if the form has been submitted to a WEB server. And this should be useful, isn't it? Many developers will ask "why if I am able to submit directly to the server?". And of course they will be right, but remember it is possible to views some pages offline (not connected to the Internet). And with our product ALP it is quite possible to have entire active site with ASP pages and other CGI scripts running directly from a CD on the user's machine. And here comes a reason to use mailto: protocol - to make possible to receive offline requests without need of no other software except a configured mail client on the machine. Well there is no guarantee that the user uses IE compatible mail client or so, but in most cases your application will have a chance to send the data. I've tested this with IE and Outlook from MS office (2000) and Outlook Express (4 and 5). I have problems on NT4 with Outlook Express but in all the other cases it worked.
Thus I decided to write this example. It contains the following parts:
Well, think for the sample as for two - a simple one and extended example which can be used as a starting point for an application. Both examples require the components mentioned above to be installed on the test machine - the machine that extracts and processes the mail and the ASP pages in the second sample.
The simple example
What you need?
A mail server and a POP3 account on it. I suggest you to create one mail
box for the tests.
A machine where the scripts will run with access to the mail server. There you
will need to register:
newobjectspack1.dll (AciveX Pack1 comes with install utility), URLEncHelper.dll
- from the sample's archive, and zakspop3.dll from the Zaks solutions WEB site.
A machine where the HTML pages will be opened and the mail client is configured
and works fine with the browser.
Of course everything can be arranged on a single machine.
The sample shows how this all works. Use one of the HTML forms, modify it to send the mail to a the test mail account on your mail server, install the components on the test machine (any machine with access to your POP3 server) and start the script. Open a console (MSDOS window) go to the sample directory and use the cscript.exe sample.vbs on the command line. Of course you will need to edit it first - change the POP3 server address, username and password to match your test mail account - see the constants in the beginning. If you do not have Windows Scripting Host (cscript.exe) install it first.
If everything is ok you will see the messages listed and a dump of the field values for the messages with a form post attachment. As in any other WEB application fields can be repeated thus collection is a collection of collections - like the Request.Form in ASP. It returns empty variant if you are trying to access a missing field. Here is a sample output:
TOTAL MESSAGES ON THE SERVER: 1 Message 1: Form posted from Microsoft Internet Explorer. Part 1 seems to be attachment - processing ... 3 Fields -> F1 [1] = Write something here -> F2 [1] = F2 Value 1 -> F3 [1] = Yes ======================================================
Lets take a closer look at some parts of the sample code:
Of course there is some work to be done - accessing the mail server and fetching the messages. Then over each message we search for the attached file:
For Each att In msg.BodyParts If att.IsAttachment Then
The mail messages are sent as multipart data if attachments are present. So we need to cycle through the parts and work only with the parts that are attachments.
WScript.Echo "Part " & n & " seems to be attachment - processing ..."
strAtt = att.Body
' Ensure no new line characters are present in the string
' JMail bug
l = Len(strAtt)
For i = 0 To l-1
s = Mid(strAtt,l-i,1)
If s <> vbCr And s <> vbLf And s <> vbTab And s <> " " Then
strAtt = Left(strAtt,l - i)
Exit For
End If
Next
Now we have the URL encoded (still not sure if it is URL encoded) attachment and we need to try to decode it. The parts in the multipart data end with new-line so we need to clean it (some other mail components will remove it but above code will do no harm). And now the most interesting part follows - decoding the data:
On Error Resume Next
Set vars = dec.Decode(strAtt)
If Err.Number <> 0 Then
WScript.Echo "The Attachment is not a standard form post"
Else
On Error Goto 0
DumpVars(vars)
End If
End If
n = n + 1
Next
dec is an instance of the URLEncHelper ActiveX - created as usual: Set dec = CreateObject("newObjects.utilctls.URLDataDecoder"). So the DumpVariables function uses the result returned by the dec.Decode and looks like this.
Sub DumpVars(v)
Dim i,j
WScript.Echo v.Count & " Fields"
For i = 1 To v.Count
WScript.Echo "-> " & v.Key(i)
For j = 1 To v.Item(i).Count
WScript.Echo " [" & j & "] = " & v(i)(j)
Next
Next
End Sub
It enumerates the returned collection in manner very similar to the way we will enumerate Request.Form in ASP. The collections are based on the VarDictionary and UtilStringList classes from ActiveX Pack1. So the decoded data is a collection of sub-collections - each named with the corresponding field name in the submitted form and each collection contains 1 or more values. 1 - if the field exists only once in the form and more if the field name is used more than once - one entry per each occurrence. The Key property returns the name of the indexed item - so it is a way to learn the names of the fields without knowing them.
In "real" situation - e.g. application that does something useful we will probably know the field names. And, for example, if we need to check some fields only we can do something like this:
On Error Resume Next
Set vars = dec.Decode(strAtt)
If Err.Number <> 0 Then
WScript.Echo "The Attachment is not a standard form post"
Else
On Error Goto 0
' *** The sample code ***
If vars("F2") <> "" Then
' For example open a DB and insert a record
Set db = db.Open "SomeDB"
db.Execute "INSERT INTO SomeTable (Field1, Field2) VALUES ('" & _
vars("F1") & "','" & vars("F2") & "')"
End If
End If
In other words we have the "mail post" in the vars collection and we can do whatever we want with it. One funny idea is to respond with mail message to the user - this will look like WEB server but through e-mail. And why not? Some services will only benefit of such kind of functionality - the user may want to request news, actual information specifying some parameters (for example region or time interval).
The extended sample
The extended sample shows how we can update a data base from the received data. The sample is not explained in details here but it follows exactly the same steps and the difference comes from the fact that it uses the received data for something more than just variables dump. In other words it illustrates how an application can be created over this feature.
When you are ready with the first example to run this one you will need to edit the dbsample.vbs set the path to the sample.mdb in it and again the POP3 account settings (as in the other file - sample.vbs). This script has a very little output and in real situation should be configured with the task scheduler to run frequently and collect the requests. Note that this script deletes the processed messages (one more reason to use a test mail account and not yours). If it runs ok you can view the db using the two ASP pages - errlist.asp lists the errors reported by the dbsample.vbs script and the other msglist.asp lists the correct messages received (from today only). If you do not have a WEB server on the machine where the scripts run download ALP and run them directly on the desktop.
The ASP part of the sample is typical and deserves no special attention. But the other part - dbsample.vbs can be used in different manners. First of all it is intended for asynchronous usage - e.g. a functional application will probably use the scheduler to run this script once per several hours or it can be adopted for something like the Script Service. Anyway the idea is simple and I hope interesting - we can receive meaningful form posts through e-mail without need of any expensive software on the both ends - client and the server. as you can see the basic functionality requires a little efforts only and everything else ... with or without message queuing software it is a logic specific to the application. And we do not need to convince the user to install anything - the form can be submitted from a HTML page saved on the local hard disk.
URLEncHelper is implemented in C++/ATL/Jacked-Objects. If you want to
recompile it see the readme.txt in the source directory for more information. It
contains only one class:
ProgID: newObjects.utilctls.URLDataDecoder
ClassID: {83D26E1E-66CE-4CD3-8199-92986F744ACB}
It exposes one method Decode:
Set vars = object.Decode(PostString)
PostString is URL encoded form post, vars receives the decoded/parsed collection of the form fields. vars is a collection and can be used in For Each constructions, supports Count and Key properties. It is implemented using the VarDictionary and UtilStringList objects from ActiveX Pack1 - see their documentation for more information. In general its behavior is almost the same as Request.Form in ASP.
mailto.zip - This article and the sample scripts and pages. The C++ source code of the ActiveX is included. It needs Jacked-Objects library in order to compile (but the C++ part is out of the topic - the component is free of course).
Used components: ActiveX Pack1, Zaks JMail - if you want to use another POP3 component you will need to change the code. I selected this one because it is free and also seems to work better than most of the other components I tried (even some of the commercial ones).
Note: all the mentioned script files, pages and the database are in the src subdirectory of the zip file.
Copyright newObjects and Michael Palazov - Elfial 2002