Table of Contents
This chapter discusses the tools offered by Biferno to handle email from a
script using the methods of the smtp class.
The simplest way to send an email message from a Biferno script is by using
the SendMail static method, with the following prototype:
static string SendMail(string host, string from, string to, string text)
The host parameter specifies the name or address of the SMTP server we want
to use to send our email. The from parameter specifies the email address to
be used as the address of the sender of the message. The to parameter is
the email address of the receiver, i.e. the person we want to address the
message to. The text parameter is the message text, possibly including part
of the SMTP header (in particular the subject field).
The following script shows how to use the SendMail method:
<?
email_host = "mailserver.mydomain.com"
email_from = "me@mydomain.com"
email_to = "him@hisdomain.com"
email_text = "Subject: SendMail Test\r\n\r\n"
email_text += "Test email body."
status = smtp.SendMail(email_host, email_from, email_to, email_text)
?>
Notice that in our example the message text contains a first line starting
with the word "Subject" followed by the ":" character (semicolon) and by
the subject text. This line is the header of our message. The body of the
message must be separated from the header by two new lines (each of them
being the combination of the characters CR, carriage return, and LF, line
feed).
In the message header it is also possible to insert other fields that are
specific to the SMTP header, such as "Cc:" (carbon copy) and others,
separated by a single new line character combination (CR+LF). The exact
syntax is therefore: field_name + semicolon + value + CR + LF.
The SendMail method returns a string containing the description of an error
(or warning) generated by the SMTP server. This allows us to verify if the
message has been correctly sent. If errors in the parameters are
discovered (e.g. a wrong SMTP server name), the SendMail method generates
an error of the smtp class.
The SendMail method sends the message synchronously, which implies that
script execution may block for several seconds waiting for an answer from
the SMTP server. Additionally, no resend attempts take place if sending a
message fails on the first attempt, and the email will not be sent to
destination (unless the script is run again).
The smtp class also supports asynchronous sending of email, i.e. without
waiting for an answer from the SMTP server.
To send asynchronous email messages, the smtp class makes the SendMailAsync
static method available, with prototype:
static string SendMailAsync(string host, string from, string to,
string text, string filePath, unsigned minutes)
This method has two additional optional parameters with respect to the
SendMail method. The filePath parameter specifies the path of the spool
file where Biferno temporarily stores the message while it waits to be sent to
the server. If this parameter is not passed, Biferno uses a default name
for the spool file. The minutes parameters defines the timeout, in minutes,
after which Biferno will stop trying to send the message in case of
repeated errors. The default timeout is five minutes.
The SendMailAsync works in a simple fashion. When the method is called, the
email message is stored in a special format (XML) within the file specified
by the filePath parameter. The ".xml" extension is added automaticaly to
the file name. Once this step is completed, Biferno continues to process
the current script with no further interruption, while another process
running in parallel has the task of asynchronously sending the queued
messages.
If an error occurs, Biferno will try to send the message again at regular
intervals, until the timeout specified by the minutes parameter is reached.
For this reason using the SendMailAsync method not only makes script
execution faster, but also increases the likelihood that a message can be
successfully sent in presence of temporary error conditions.
All attempts to send a message, i.e. the conversational protocol exchanges with the SMTP server, are stored in a log file in the same directory as the message file. The log file has the same name of the message file with the extension ".log" appended. The message file, together with the corresponding log file, is deleted from disk after the message has been successfully sent or after the timeout period expires.
The SendMailAsync method returns a string containing the file path of the
message, including the name with which it has been stored on disk. The
filename is returned because a default is used if no parameter was passed,
because the ".xml" extension is appended automatically, and finally
because, if the file specified by the filePath parameter already exists,
the method appends a progressive number to the file name.
The following script shows how to use the SendMailAsync method. The script
sends a message to a number of email addresses stored in an array, which
could be filled e.g. by a database query.
<?
email_host = "mailserver.mydomain.com"
email_from = "me@mydomain.com"
email_text = "Subject: SendMailAsync Test\r\n\r\n"
email_text += "Test email body."
email_timeout = 120 // Two hours
arr_email = array("user1@domain1.com", "user2@domain2.com",
"user3@domain3.com", "user4@domain4.com")
n_email = arr_email.dim
email_sent = 0
for (i = 1; i <= n_email; i++)
{
email_to = arr_email[i]
if (email_to.IsEMail())
{
email_sent++
email_file = "emails/email_" + email_sent
smtp.SendMailAsync(email_host, email_from, email_to,
email_text, email_file, email_timeout)
}
}
?>
The smtp class allows to verify, within the set timeout, individual email
messages that are still stored on disk because of a persistent error
condition that caused automatic send attempts to fail (recall that messages
are deleted from disk anyway after timeout).
The ParseMailFile static method reads a file containing an email message in
the format generated by the SendMailAsync method and returns an associative
array containing the various elements of the message. This method has the
following prototype:
static array ParseMailFile(string filePath)
The filePath parameter specifies the path of the file to be examined. The
associative array returned by this method contains six elements with the
following indices:
sm_timeout
sm_host
sm_from
sm_to
sm_body
sm_last_error
sm_creation_secs
The element with index sm_last_error contains the description of the last
error generated by an attempt to send the message.
The element with index sm_creation_secs provides the date (in seconds from
time zero, see Chapter 14, Date and Time Functionality) of the creation of the email file.
The following script shows how to verify the existence of email files
corresponding to unsent messages in the directory specified in the path
passed to the SendMailAsync method and, at the same time, how to offer to
the application user the option of manual sending.
<html>
<body>
<h2>Queued messages list</h2>
<?
function int ListMessages(string filePath, long variant)
{
if (msg = smtp.ParseMailFile(filePath))
{
global queued_msg++
print("<b>Message nr. " + global queued_msg + "</b><br>")
print("From: " + msg["sm_from"] + "<br>")
print("To: " + msg["sm_to"] + "<br>")
arr_msg = msg["sm_body"].ToArray("\r\n")
print(arr_msg[1] + "<br>") // Print subject
print("<a href=send_message.bfr?msg_path=" + filePath.UrlEncode() + \
"><b>Send now</b></a><br><br>")
}
return 0
}
global queued_msg = 0
email_dir = folder("emails/")
email_dir.Walk("", false, "ListMessages")
if (global queued_msg == 0)
print("No messages queued.")
?>
</body>
</html>
Using the Walk method of the folder class, the script examines the content
of the directory where files generated by the SendMailAsync method are
stored and, for each such file, displays the from, to and subject message
fields, associated to a link to another script ("send_message.bfr") that
sends messages in a synchronous fashion.
A very simplified version of the "send_message.bfr" script could look as follows:
<html>
<body>
<?
status = smtp.SendMailFile(msg_path)
if (status == "")
print("Message sent.")
else
print("ERRORE! " + status)
?>
</body>
</html>
This script accepts as input the path of the file corresponding to the
message to be sent and sends it using the SendMailFile static method, with
prototype:
static string SendMailFile(string filePath)
This method verifies the content of the file corresponding to the filePath
path, assembles the message, sends it synchronously, and, if no errors
occur, deletes the file. If an error occurs, a string containing the error
description is returned and the file is not removed from disk. The
SendMailFile method also generates a log file, which is deleted along with
the message file if sending is successful.