Simple SMTP Client

 < Day Day Up > 



The simple Tcl SMTP client (lines 1-99) in Listing 21.10 is made up of only two procedures, the main procedure for sending the e-mail (Mail_Send, lines 42-99) and the dialog procedure (dialog, lines 4-36) for communicating dialog transactions with the SMTP server.

Let's look at the SMTP client in the reverse order. We first discuss the dialog procedure and then its user, Mail_Send. The dialog procedure (lines 4-36) provides the ability to send a command and receive a response from the SMTP server. The caller may optionally specify no command, or no response. If a response is specified, the response is expected from the server and is verified with what the server actually returned.

Line 4 begins with the definition of the dialog procedure. The dialog procedure expects three arguments from the caller: the client socket, string command, and string response. At line 7, we check to see if the caller specified a command to send by testing the length of the command using the string command with the length option. If the length is greater than zero, a command is present and is then sent through the socket at line 9 using the puts command. Note that the -nonewline option is specified. We'll allow the caller to add its newline if needed for the command.

At line 15, we begin checking for a response. If a response is expected (again identified by the string length of the exp_response argument), we get a line of text from the socket using the gets command at line 18. Recall that the first three characters of an SMTP server response represent the response status code. At line 21, the first three characters are extracted from the line read through the socket and stored in stscode. We then compare the response code extracted from the server response to the response code that the caller expected at line 25 using the string compare command. The result is stored in check, and then tested at line 27 (non-zero means that the strings did not compare successfully). If the response codes were not equal, we issue an error, otherwise we simply return. The error command is a mechanism to raise errors to calling procedures, which we discuss in the Mail_Send procedure.

The Mail_Send procedure (Listing 21.10, lines 40-99) performs the actual SMTP client protocol. It uses the dialog procedure to perform the actual command transactions with the server, and is, therefore, very simple because the input and output operations are abstracted away.

The Mail_Send procedure accepts a number of arguments for defining the location of the outgoing mail server (mail_server) as well as the e-mail to be sent. The e-mail is defined by the subject (the subject to be shown in the e-mail), the sender (who this e-mail will be shown as arriving from), the recipient (the e-mail address for whom this e-mail is directed), the content-type (how the body of the e-mail should be rendered by the receiving client), and, finally, the e-mail body itself (contents).

We begin at line 46 by creating the client socket (using the socket command) and connecting it to the mail_server defined by the caller and the standard SMTP server port (25). Once the socket is connected, we configure the socket for line buffering (line 49) using the fconfigure command. At line 52, we use the catch command. The catch command catches errors that may occur in the script block within the catch command. If an error is raised in the script, the script is exited and a 1 is returned to indicate that an error occurred. Otherwise, a 0 is returned indicating that no error occurred. The catch block, therefore, allows us to catch any errors that are raised for any of the dialogs, and immediately exit the script within the catch block. The error is stored within variable err (as shown at line 52).

Within the catch block (lines 55-86), we perform our dialogs with the SMTP server. These won't be detailed here because they are discussed in detail in Chapter 15, Software Patterns Introduction. Each dialog potentially issues a command and in most cases awaits a valid response from the server. Upon completion of the dialogs, we check our error status (line 91) and if an error occurred, we simply issue a warning to standard-out using the puts command to notify the user. The socket is then closed at line 97 using the close command.

The final step in Listing 21.10 is calling the Mail_Send procedure at line 105 to send an e-mail. This step specifies the outgoing mail server, subject line, sender and recipient, content type, and, finally, the message body.

Listing 21.10 Simple Tcl SMTP client source.

start example
  1   #   2   # Perform a dialog with the SMTP server   3   #   4   proc dialog { sock command exp_response } {   5   6     # Send the command if the user provided one   7     if { [string length $command] > 0 } {   8   9       puts -nonewline $sock $command  10  11     }  12  13     # Only check for a response if the user defined the  14     # expected response code  15     if { [string length $exp_response] > 0 } {  16  17       # Get a single line from the connection  18       set line [ gets $sock ]  19  20       # Parse the status code from the line  21       set stscode [ string range $line 0 2 ]  22  23       # Check the status code from the server with the  24       # response code that's expected  25       set check [ string compare $stscode $exp_response ]  26  27       if { $check != 0 } {  28  29         # Not what was expected, raise an error  30         error "bad dialog"  31  32       }  33  34     }  35  36   }  37  38  39   #  40   # Send the mail based upon the defined parameters  41   #  42   proc Mail_Send { mail_server subject sender recipient  43                    content_type contents } {  44  45     # Create and connect the client socket  46     set sock [ socket $mail_server 25 ]  47  48     # Configure for immediate receipt  49     fconfigure $sock -buffering line  50  51     # Catch any errors that occur  52     set err [ catch {  53  54       # Look for the initial e-mail salutation  55       dialog $sock "" "220"  56  57       # Send HELO and await response  58       dialog $sock "HELO thisdomain.com\n" "250"  59  60       # Send "MAIL FROM" command and await response  61       dialog $sock "MAIL FROM: $sender\n" "250"  62  63       # Send "RCPT TO" command and await response  64       dialog $sock "RCPT TO: $recipient\n" "250"  65  66       # Send "DATA" to start the message body  67       dialog $sock "DATA\n" "354"  68  69       # Send out the mail headers (from/to/subject)  70       dialog $sock "From: $sender\n" ""  71  72       dialog $sock "To: $recipient\n" ""  73  74       dialog $sock "Subject: $subject\n" ""  75  76       # Send the content type  77       dialog $sock "Content-Type: $content_type\n\n" ""  78  79       # Send the actual message body  80       dialog $sock "$contents" ""  81  82       # Send the end-of-email indicator  83       dialog $sock "\n.\n" "250"  84  85       # Finally, close out the session  86       dialog $sock "QUIT\n" "221"  87  88     } ]  89  90     # Emit to standard-out if an error occurred  91     if { $err } {  92  93       puts "Couldn't send mail"  94  95     }  96  97     close $sock  98  99   } 100 101 102   # 103   #  Send a test e-mail 104   # 105   Mail_Send "mtjones.com" "The Subject" 106             "tim@mtjones.com" "mtj@mtjones.com" 107             "text/html" 108             "<HTML><BODY><H1>This is the mail</H1></BODY></HTML>" 109 
end example



 < Day Day Up > 



BSD Sockets Programming from a Multi-Language Perspective
Network Programming for Microsoft Windows , Second Edition (Microsoft Programming Series)
ISBN: 1584502681
EAN: 2147483647
Year: 2003
Pages: 225
Authors: Jim Ohlund

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net