Simple SMTP Client

 < Day Day Up > 



Now, let’s look at a simple SMTP client written in Perl (see Listing 19.10). The Perl implementation is made up of two subroutines, Mail_Send (lines 45–108) and dialog (lines 6–39). The Mail_Send subroutine is the main entry point for sending e-mails, whereas the dialog is a support function that provides the ability to send commands and receive and verify responses from the SMTP server, thus simplifying the overall complexity of Mail_Send.

We discuss the dialog subroutine first, and then look at the Mail_Send subroutine that actually provides the meat of the SMTP client protocol.

Subroutine dialog (lines 6–39) provides the means to perform a single dialog with the SMTP server. Recall that SMTP is a command and response protocol, so dialog provides the mechanism to send a command and then conditionally await and check an associated response. Subroutine dialog is provided the client socket ($sock), the optional command to send ($command), and the optional response code that should be matched against the potential response ($exp_resp). The shift operator is used to gather the arguments from the @ARGV list (lines 8–10). The $command is tested at line 13 to see if a command does exist, and if so, the send function is used to send this command through the client socket to the SMTP server (line 15). The $exp_resp is tested at line 21 to see if the caller is expecting a response. This variable contains a three-digit SMTP status code that will be used to verify that the SMTP server accepted and processed our optional $command properly. If the caller expects a response, the response is read from the socket at line 24 using the recv function. At line 27, we grab the first three digits from the line (which represent the status code from the SMTP server) and then at line 31, we test this with our $exp_resp variable. If they don’t match (an error has occurred), we cause an exception using the die operator with a simple error message. Otherwise, we simply return and allow control to continue at the caller (Mail_Send).

The Mail_Send subroutine (lines 45–108) implements a very simple version of the SMTP client protocol. Six arguments are provided to Mail_Send that completely identify both the e-mail to send and the destination SMTP server (Mail Transfer Agent) to which the e-mail will be transported. The first argument ($mail_server) defines the destination address of the SMTP server to which we’ll communicate (otherwise known as the Mail Transfer Agent, or MTA). The $subject is the subject line of the e-mail, and $sender and $recipient are the source and destination e-mail addresses, respectively. The $content_type is the string content type that is used to identify how the receiving e-mail client (Mail User Agent, or MUA) should render the body of the e-mail. If we’re sending an e-mail that contains HTML tags, we’ll specify a content type of “text/html”; otherwise, we’ll use the default “text/plain”. Finally, the $contents variable is used to specify the e-mail body itself. These arguments are shifted from the @ARGV list at lines 48–53.

At line 56, the client socket is created using a type of Socket::SOCK_STREAM (TCP, stream socket). In order to connect to the SMTP server, we must next create an address structure representing the address and port to which we’ll connect. We first take the mail server address represented by $mail_server (line 61) and convert this into a binary, 32-bit address ($addr) using inet_aton. This new address, along with the SMTP port 25 is passed to sockaddr_in to create our packed address, $paddr (line 62). With this new packed address, we can connect to the remote SMTP server using the connect function (line 65).

The remainder of Mail_Send is a very simple version of the SMTP client protocol. The dialog subroutine is used to perform the command/response transactions with the SMTP server. As this is discussed in Chapter 15, Software Patterns Introduction, we discuss only a couple of dialogs here to illustrate the Perl functionality. At line 68, we await the SMTP salutation from the SMTP server. No command is sent, because the salutation should be emitted immediately after connect. Therefore, we provide no command, and simply await the “220” response status code. The next example, line 71, begins the client side of the session by issuing a HELO command. This command is used to identify us to the SMTP server. We send the HELO command with a bogus domain (should be the domain from which we connect), and expect back a status response code of “250”.

The remainder of this function represents the SMTP client for sending a simple e-mail (lines 73–103). Recall from the dialog subroutine that if an incorrect status response code is received, the client will die, severing the connection to the server and, therefore, the SMTP session. If we successfully complete the dialogs in Mail_Send, we close the client socket at line 106 using the close function.

The final element of the SMTP client is the sample client invocation at lines 114–120. We invoke the Mail_Send subroutine, specifying the mail_server and the e-mail that we want to send. Note at lines 119 and 120, the period (‘.’) is used to concatenate the contents string argument together.

Listing 19.10 Perl language SMTP client source.

start example
  1   use Socket;   2   3   #   4   #  Perform a dialog with the SMTP server   5   #   6   sub dialog {   7   8     $sock = shift;   9     $command = shift;  10     $exp_resp = shift;  11  12     # Send the command if the user provided one  13     if ( $command ne "" ) {  14  15       send( $sock, $command, 0);  16  17     }  18  19     # Only check for a response if the user defined the  20     # expected response code.  21     if ( $exp_resp ne "" ) {  22  23       # Get a line from the connection  24       recv( $sock, $line, 128, 0 );  25  26       # Parse the status code from the line  27       $stscode = substr( $line, 0, 3 );  28  29       # Check the status code from the server with the  30       # response code that's expected.  31       if ( $stscode ne $exp_resp ) {  32  33         die "Error sending mail";  34  35       }  36  37     }  38  39   }  40  41  42   #  43   #  Send the mail based upon the defined parameters  44   #  45   sub Mail_Send {  46  47     # Grab the arguments  48     $mail_server = shift;  49     $subject = shift;  50     $sender = shift;  51     $recipient = shift;  52     $content_type = shift;  53     $contents = shift;  54  55     # Create a stream socket  56     socket( SOCK, Socket::AF_INET,  57              Socket::SOCK_STREAM, 0 ) or  58       die "socket: $!";  59  60     # Create a packed address  61     $addr = inet_aton( $mail_server );  62     $paddr = sockaddr_in( 25, $addr );  63  64     # Connect to the server  65     connect( SOCK, $paddr ) or die "connect: $!";  66  67     # Look for the initial e-mail salutation  68     dialog( SOCK, "", "220" );  69  70     # Send HELO and await response  71     dialog( SOCK, "HELO thisdomain.com\n", "250" );  72  73     # Send "MAIL FROM" command and await response  74     $tempstr = "MAIL FROM: " . $sender . "\n";  75     dialog( SOCK, $tempstr, "250" );  76  77     # Send "RCPT TO" command and await response  78     $tempstr = "RCPT TO: " . $recipient . "\n";  79     dialog( SOCK, $tempstr, "250" );  80  81     # Send "DATA" to start the message body  82     dialog( SOCK, "DATA\n", "354" );  83  84     # Send out the mail headers (from / to / subject)  85     $tempstr = "From: " . $sender . "\n";  86     dialog( SOCK, $tempstr, "" );  87     $tempstr = "To: " . $recipient . "\n";  88     dialog( SOCK, $tempstr, "" );  89     $tempstr = "Subject: " . $subject . "\n";  90     dialog( SOCK, $tempstr, "" );  91  92     # Send the content type  93     $tempstr = "Content-Type: " . $content_type . "\n";  94     dialog( SOCK, $tempstr, "" );  95  96     # Send the actual message body  97     dialog( SOCK, $contents, "" );  98  99     # Send the end-of-email indicator 100     dialog( SOCK, "\n.\n", "250" ); 101 102     # Finally, close out the session 103     dialog( SOCK, "QUIT\n", "221" ); 104 105     # Close the client socket 106     close( SOCK ); 107 108   } 109 110 111   # 112   #  Create a new HTTP server and start it on port 80 113   # 114   Mail_Send ("192.168.1.1",  115              "The Subject",  116              "tim\@mtjones.com",  117              "mtj\@mtjones.com", 118              "text/html", 119              "<HTML><BODY><H1>This is the mail" .  120               "</H1></BODY></HTML>" );
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