"You've got a potential trademark violation!"
Director has very strong net integration features. You can access data
from web pages, download files from servers and even communicate with
CGIs. But most importantly, you can access and monitor the status of
these processes and report back to the user if there is an error or
problem. If you want to send email from Director though, you are not so
lucky. Director has no native functions that handle processing email, with
the result that you have to rely on other means if you want to send mail
from within Director.
This article will discuss three ways to send email in Director. Using
gotoNetPage, connecting with a server side CGI or by using the
DirectEmail Xtra from DirectXtras.
gotoNetPage
Perhaps the simplest way to attempt to send an email message via Director
is to use the gotoNetPage command and use a mailto URL instead of an http
URL. The mailto format is quite simple.
mailto:<address>
or
mailto:zac@director-online.com
Test it out. Open Director, open the Message Window and enter
gotoNetPage "mailto:zac@director-online.com"
and then hit RETURN.
If your system is configured properly then your designated email client
should activate and display a new email message with the To: recipient
filled out with my email address.
The mailto URL can also be passed an optional subject which is separated
from the email address by a query marker (a question mark to the rest of
the world). That subject has to be URL encoded in order for your email
client to be able to process any spaces or special characters. So if you
wanted to send me a an email message with the subject "Hi Zac" you might
use...
thisSubject = "Hi Zac"
thisSubject = os_URLEncode(thisSubject)
url="mailto:zac@director-online.com?subject=" & thisSubject
gotoNetPage url
Notice that in the example I do not use the URLEncode() function provided
in Director 7. That is because the function that comes with Director 7
converts spaces in a string to a +. Most email clients (and browsers I
suspect) will have problems with this as they will expect spaces to be
encoded as %20 instead. So I have written my own function to "properly"
encode the strings. The code for the function (with a few supplementary
functions it calls) are in the sample movie.
While this is a very simple way to create an email message there are
several problems with it. First, you can't uniformly specify the body of
the message or any of the other recipients. So if you want to add CC and
BCC recipients, as well as define the message body you may or may not be
able to do this depending on how much information your user's email
client will parse from a mailto URL. Some might and some might not. So
unless you know what email client the user has, it is a bit of a crap
shoot to attempt to send more data than the To: address and the subject.
Secondly, even though you can create a message there is no guarantee
that you can get the user to send it. All a mailto URL will do is create
the message. The user still has to send the message themselves.
Thirdly, you can't monitor the progress of the process. Once you make the
gotoNetPage call you've lost control of the process. This means you can
not provide any feedback to the user if there is an error. Or even know
if there is an error.
Finally, gotoNetPage is notoriously flaky when it comes to processing
mailto URLs. This isn't a result of any problem with Director but in the
way that most browsers and operating systems deal with mailto URLs. If
the user's system is not configured properly they will quite often see
their web browser open and then it will open/activate their email client.
In some extreme circumstances, the browser is misconfigured and won't be
able to pass the mailto URL to the email client. And since you can't
track the process you have no way to know if this happens.
All in all not an optimal solution.
Server side CGI
A better solution is to use a server side CGI to send the email. This
requires that a CGI exists on your server to handle the task of actually
sending the mail. Most ISPs have standard CGIs available for their
clients, and if not, you can find numerous examples at sites like the CGI
Resource Index. Communicating with the CGI is quite simple with Director 7 since it has a
postNetText function that works in the same fashion that most web
based forms do. The following example will be a bit vague as this
article has (for reasons that will become clearer later on) no sample
CGI. Instead we will deal with more general issues surrounding the topic.
Let's assume that you are sending data to a CGI that allows you to supply
the following data: to, from, subject, CC and messageBody. If these data
elements were all supplied from fields in your Director project then you
could communicate this data by creating a postNetText call.
toRecipient = member("toField").text
fromRecipient = member("fromField").text
subject = member("subjectField").text
ccRecipient = member("ccField").text
body = member("bodyField").text
thisURL = "http://www.somedomain.com/cgi-bin/formMail.cgi"
propList = [#to: toRecipient, #from: fromRecipient, ¬
#subject: subject, #cc: ccRecipient, # messageBody: body]
thisNetId = postNetText (thisURL, propList)
postNetText is very similar to getNetText. It takes a URL and a property
list (or a series of string data) and returns a network ID that you can
use to track the progress and results of the network call. So any network
code that you have (or have lifted from articles dealing with
communicating with CGIs
will work with postNetText calls with little or no modification.
For the postNetText call to actually send the data to the CGI you need to
provide a property list with a property for each data element you want to
send to the CGI. As mentioned before our example CGI needs to, from,
subject, CC and messageBody data elements. So the property list we build
in the code sample above provides a symbol and string for each data
element. This data will be sent to the CGI.
You can also send the data as plain strings but if you do this the data
is sent as "text/html" and this may not be compatible with most CGIs.
While using a server side CGI does give you more control over the
emailing process there are also downsides. First, most CGIs are written
in Perl. This is fine if you know Perl or have access to a Perl
programmer but if you aren't experienced with it then modifying a Perl
CGI can be a bit daunting.
Secondly, Perl scripts (and most CGIs) can be rather problematic to
install and get running. I know that
some people will disagree with this but my experience has been that Perl
configuration is something best left to the experts. On the plus side,
once the CGIs are installed and configured they usually run with no
problems.
Thirdly, most of the easily available CGIs will be written for use in web
pages and will report their data in a fashion that might not be optimal
for use in Director or Shockwave. This means that you will most likely
have to rewrite some of the CGI in order to customise the data it returns
in order to be able to report back to the user about the status of the
message.
DirectEmail Xtra
Perhaps the best solution is to use the DirectEmail Xtra
from DirectXtras. The xtra is cross-platform and is also Shockwave safe
(check out this Shockwave version of the sample movie) meaning that you can create and deliver email solutions
to a wide range of users with it. The xtra is also relatively easy to use
and allows you to contain the entire messaging process inside Director.
A sample movie is available for download in Mac or PC format. This is a Director 7 movie
The xtra has very few methods
- New ( Xtra "DirectEmail", string mailServer, string MailboxName, string
Password )
creates a new instance of the Xtra
- SendEmail ( object me, string From, string To, string CC, string BCC,
string Subject, string Body, string Attachment )
creates and send the email message. Returns FALSE if the xtra is currently busy sending another email message
- EmailDone ( object me )
like netDone() it returns TRUE if the email process has been completed
- EmailErrorCode ( object me )
returns the last error code generated for the xtra's instance
- EmailErrorMessage ( object me )
returns a "friendly" message to pass back to the user
- EmailAbort ( object me )
stops the email process
- GetUserEmailPref ( integer InfoToLocate )
A Mac only function that returns that user's default email address and
mail server address if they have InternetConfig installed on their machine
The process of using the Xtra to send an email message is very straightforward.
Step 1
The first thing you will need to do is create an instance of the xtra.
This is done using the new method. You need to provide the xtra with the
address of the mail server that the xtra will attempt to send mail
through. This can either be provided by the user or, more likely, hard
coded by you.
global gEmail
gEmail = new (Xtra "DirectEmail", "mail.somedomain.com", ¬
"", "")
Once you've created the instance of the xtra you need to store it either
in a global variable or in an object property so you can refer to it
later. Note that the last two parameters (mailBoxName and password) are
not currently used in this version of the xtra so you just supply blank
strings instead.
Step 2
Now you need to gather the actual information that will make up the email
message. In the sample movie this is done by getting the contents of a
series of the fields that the user enters their data in. First you would
get the data from the fields...
messageHasErrors = FALSE
errorMessage = ""
recipients = member("To").text
fromAddress = member("From").text
mailServer = member("MailServer").text
CCRecipients = member("CC").text
BCCRecipients = member("Bcc").text
body = member("Body").text
attachment = member("Attachment").text
subject = member("Subject").text
then store it somewhere convenient, like a property list, for easy
reference...
-- store all the data in a nice property list
messagePropList = [#to:recipients, #from: fromAddress, ¬
#server:mailServer, #CC:CCRecipients, ¬
#BCC:BCCRecipients, #body:body, #subject:subject, ¬
#attachment:attachment]
...and then do some tests to make sure that the user has entered data. You
might also want to test the validity of the data to ensure that they
enter valid email addresses and, if necessary, a valid mail server
address. The code for the isValidEmail() function and the
emailValidationError () are both in the sample movie. In this instance
we're just testing the To: and From: addresses.
if recipients = EMPTY then
messageHasErrors = TRUE
errorMessage = errorMessage & "You need to ¬
specifiy at least one recipient" & RETURN
end if
if fromAddress = EMPTY then
messageHasErrors = TRUE
errorMessage = errorMessage & "You need to ¬
an email address to send the message from" & RETURN
end if
-- check to see if the email addresses are valid
toAddressHasErrors = isValidEmail (messagePropList.to)
fromAddressHasErrors = isValidEmail (messagePropList.from)
if toAddressHasErrors then
messageHasErrors = TRUE
errorMessage = errorMessage & "The To: address ¬
you supplied is not valid because" && ¬
emailValidationError (toAddressHasErrors) & RETURN
end if
if fromAddressHasErrors then
messageHasErrors = TRUE
errorMessage = errorMessage & "The From: address ¬
you supplied is not valid because" && ¬
emailValidationError (fromAddressHasErrors) & RETURN
end if
If there are no errors then it's safe to send the message data to the
instance of the Xtra that was created earlier.
if NOT messageHasErrors then
isOkayToSend = sendEmail (gEmail, ¬
messagePropList.from, messagePropList.to, ¬
messagePropList.cc, messagePropList.bcc, ¬
messagePropList.subject, messagePropList.body, ¬
messagePropList.attachment)
else
alert errorMessage
end if
Step 3
Now we just have to wait until the process is complete. The DirectEmail
Xtra has a function, emailDone(), that can be tested to see if the
process is complete. This is very similar to using netDone() to see if a
network process has completed. Except that you use a reference to the
xtra's instance instead of a network ID. You can test this function in an
exitFrame handler or, more preferably, in a stepFrame handler in an
object or behavior.
The sample movie included with this article handles all the mail
processing inside a single object in order to simplify the movie. This
doesn't mean that you have to use objects, only that the author is the
fussy type of person that uses objects for everything. It is quite simple
to test the emailDone() function in an exitFrame handler and then go to
another frame once the process is complete
global gEmail
on exitFrame
-- are we done?
if EmailDone(gEmail) then
go to frame "done"
else
member("status").text = "Waiting for results..."
end if
end
Step 4
Once you know that the mail process has been completed you need to test
the emailErrorCode() function to see if the mail has been sent
successfully.
emailHasErrors = EmailErrorCode(gEmail)
If NOT emailHasErrors then
member("status").text = "Your Message was Sent!"
else
member("status").text = "Error:" && emailHasErrors ¬
&& emailErrorMessage(gEmail)
end if
emailErrorCode() returns a zero if the process was a success or an
integer value, representing the particular error, if there was some
problem. The emailErrorMessage() will return a string describing the
error that you can use to report the problem to the user.
Part of the appeal of the DirectEmail xtra is that it allows you to test,
and report, for conditions that the other two methods don't allow you to
do. If the user's net connection was terminated in the middle of the
mailing process then the xtra will report this condition. If the mail
server the user specified has no DNS entry then you will be informed of
this and be able to pass this information back to the user. Additionally,
it allows you to initialise and control the entire process inside your
Lingo code. Meaning that you are not subject to OS configuration
problems, missing email clients or CGI peculiarities.
Details, details, details
The code in the sample movie uses the same steps that are outlined above
but it uses an object to contain all the interaction with the xtra. This
was done for two reasons. First, it simplifies the movie. The movie has,
with the exception of some utility routines, two button scripts, a
function to test the validity of the user supplied data and a "go to the
frame" exitFrame handler. It is an extremely basic movie. Secondly, it
makes it very easy to re-use the majority of the code with very little
work. Since the bulk of the code is in one object you can almost add the
code to another movie with a simple copy and paste.
In the sample movie nothing actually happens until the user hits the send
button. Then a handler, the aptly named sendMail (), tests the data. If
the data is valid it then creates a property list, creates a new object
and then passes the data off to the object. The object is stored as a
global variabe.
The object creates an instance of the xtra and stores it as a property.
The xtra isn't accessed at all except from inside the object. The object
then sends the mail data to the xtra and then adds itself to the
actorList.
Inside a stepFrame handler, the object checks to see if the email process
is complete and, if it is, it tests for any errors and reports them back
to the user. The object then destroys the instance of the DirectEmail
xtra and calls an external handler stopEmail (). The stopEmail handler
then destroys the object.
Summing up
Out of the three options discussed, the only two really usable methods
are server side CGIs and the DirectEmail Xtra. gotoNetPage might look
like a quick and easy solution but it has several potential problems that
you will not only have no control over but no way of testing for. Using a
server side CGI is a workable solution if you have experience writing
CGIs or have access to a programmer who can write, or modify, a CGI to
fit your needs. The DirectEmail Xtra is perhaps the best answer if you
want to create a self contained Director based email solution.
|