Simple SMTP Client

 < Day Day Up > 



Now, let’s look at a simple SMTP client written in the C language (see Listing 16.13). Again, we focus only on the networking elements; the remaining functions are provided on the CD-ROM.

Lines 8–14 perform the typical client socket creation and specification of the peer address to which we’ll connect. Lines 22–39 provide the ability to translate the mail server address to the raw 32-bit IP address. The source address (in the mailServer string) can either be a dotted-notation IP address (such as “192.168.1.1”) or an FQDN (such as “www.microsoft.com”). We first use the inet_addr function to attempt to convert the address by assuming it’s a dotted-notation IP address string. If we find this was not the case (at line 22), then we assume that it’s an FQDN and use the gethostbyname API function to resolve the name to a native IP address.

At line 42, we connect our client socket to the peer address as defined by the servaddr structure. The result here will be a connected socket to the peer mail server.

Lines 45–89 provide the protocol handling between this client and the SMTP server (as described in Chapter 15, Software Patterns Introduction). Note that the protocol handling is performed within a do/while loop, in which the while has a false conditional. The do/while construct in C provides a minimum of one iteration through the loop, but in this case, because the conditional is false, it will be done only once. The purpose of this construct is to permit a type of goto statement, without the goto statement. If an error occurs in the protocol handling, a break statement is performed. This statement forces a continuation of execution at the end of the loop, thereby providing goto statement functionality.

The actual dialog with the SMTP server is provided by the function dialog (shown in Listing 16.14). This handles not only sending the defined command to the server, but also checking the response status code from the server.

Finally, at line 91, we close the client socket and then return a status code to the caller identifying the success or failure of the SMTP transaction.

Listing 16.13 Simple SMTP client sendMail function.

start example
  1   int sendMail(struct mailHeader *mail)  2   {  3     int connfd, result, ret, goodMsg = 0;  4     struct sockaddr_in servaddr;  5     char mailRcpt[129];  6     char line[256];  7  8     connfd = socket(AF_INET, SOCK_STREAM, 0);  9 10     bzero((void *)&servaddr, sizeof(servaddr)); 11     servaddr.sin_family = AF_INET; 12     servaddr.sin_port = htons(25); 13 14     servaddr.sin_addr.s_addr = inet_addr(mailServer); 15 16     /* if the prior inet_addr results in a '-1' (or error), 17      * then we assume that the gateway symbolic is not a 18      * dotted-notation IP address. It must therefore be a 19      * fully-qualified domain name and we use gethostbyname 20      * to resolve it. 21      */ 22     if (servaddr.sin_addr.s_addr == 0xffffffff) { 23 24       struct hostent *hptr = 25               (struct hostent *)gethostbyname(mailServer); 26 27       if (hptr == NULL) { 28         /* Don't know what the mailServer represents... */ 29         return(-1); 30       } else { 31 32         struct in_addr **addrs; 33         addrs = (struct in_addr **)hptr->h_addr_list; 34         memcpy(&servaddr.sin_addr, 35         *addrs, sizeof(struct in_addr)); 36 37       } 38 39     } 40 41     /* Connect to the SMTP server */ 42     result = connect(connfd, (struct sockaddr *)&servaddr, 43                       sizeof(servaddr)); 44 45     do { 46 47       /* Look for initial salutation */ 48       if ( dialog( connfd, NULL, "220" ) ) break; 49 50       /* Send HELO and await response */ 51       if ( dialog( connfd, hello_msg, "250" ) ) break; 52 53       /* Send MAIL FROM and await response */ 54       sprintf(line, "MAIL FROM:<%s>\n", mail->sender); 55       if ( dialog( connfd, line, "250" ) ) break; 56 57       /* Send RCPT TO and await response */ 58       sprintf(line, "RCPT TO:<%s>\n", mail->recipient); 59       if ( dialog( connfd, line, "250" ) ) break; 60 61       /* Send DATA and await response */ 62       if ( dialog( connfd, "DATA\n", "354" ) ) break; 63 64       /* Send out the header first */ 65       sprintf(line, "From: %s\n", mail->sender); 66       if ( dialog( connfd, line, NULL ) ) break; 67 68       sprintf(line, "To: %s\n", mail->recipient); 69       if ( dialog( connfd, line, NULL ) ) break; 70 71       sprintf(line, "Subject: %s\n", mail->subject); 72       if ( dialog( connfd, line, NULL ) ) break; 73 74       if (mail->contentType[0] != 0) { 75         sprintf(line, "Content-Type: %s\n", 76                  mail->contentType); 77         if ( dialog( connfd, line, NULL ) ) break; 78       } 79 80       if ( dialog( connfd, mail->contents, NULL ) ) break; 81 82       /* Send mail-end and await response */ 83       if ( dialog( connfd, "\n.\n", "250" ) ) break; 84 85       if ( dialog( connfd, "QUIT\n", "221" ) ) break; 86 87       goodMsg = 1; 88 89     } while (0); 90 91     close(connfd); 92 93     return(goodMsg); 94   }
end example

The dialog function, as discussed previously, handles the actual communication with the SMTP server (see Listing 16.14). The caller provides the client socket, the command to be sent, and the expected response status code. In some cases, a command is not provided (as we’re only expecting a server response). In others, only a command is provided and no server response is expected. The final case provides for sending a command, receiving, and checking a response.

Lines 6–9 provide the command transmission, checking that a command is present before attempting to send using the write function. Lines 11–14 receive and check the response, if expected by the caller.

Listing 16.14 Simple SMTP client dialog function.

start example
 1   int dialog(int sd, char *command, char *resp)  2   {  3     int ret, len;  4     char line[128];  5  6     if (command != NULL) {  7       len = strlen(command);  8       if (write(sd, command, len) != len) return -1;  9     } 10 11     if (resp != NULL) { 12       ret = read(sd, line, sizeof(line)-1); line[ret] = 0; 13       if (strscan(line, resp, 3) == -1) return -1; 14     } 15 16     return 0; 17   }
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