Using MS VC++ C:9 (2008) in Windows XP 32 bits and Boost.asio:
I’ve written an application who can send/receive e-mails from/to an proprietary dBase using the POP3/SMTP protocols. The whole thing work as expected, but there are an problem in the SMTP connection process that for the moment, I’ve been unable to resolve in a generic way.
In SMTP, the whole process is a sequence of commands from the client (C:) and reading the responses from the remote server (S:). The command is sent with some as:
async_write (socket_, request_,
boost::bind(&IPCON::hndlSOKresp, this, placeholders::error));
The server response to the client’s command, is always ended with CRLF sequence, so the hdlSOKresp() function, includes some as:
async_read (socket_, response_, transfer_at_least(1),
boost::bind(&IPCON::hndlRemain, this, placeholders::error));
In turn, hadlRemain() verifies if the received buffer ends with the CRLF pair, and otherwise, calls itself recursively until the whole response has been received.
The schema work fine when -as usually-, the server response contains one line, but the command EHLO/HELLO, produce a multiline response containing the main characteristics of the server and specific of each server. As an example, there are tree responses:
1&1 Nemesis server (a knonw Internet service provider):
250-smtp.1and1.es
250-STARTTLS
250-AUTH LOGIN PLAIN
250-AUTH=LOGIN PLAIN
250-PIPELINING
250-SIZE 120000000
250 HELP
Google Gmail:
250-mx.google.com at your service, [83.61.174.109]
250-SIZE 35882577
250-8BITMIME
250-AUTH LOGIN PLAIN XOAUTH
250 ENHANCEDSTATUSCODES
Yahoo:
250-smtp212.mail.bf1.yahoo.com
250-AUTH LOGIN PLAIN XYMCOOKIE
250-PIPELINING
250 8BITMIME
The question is: how can be handled this situation?
The momentary workaround is that if I know the connection that has been used, then I can wait until the last word. I.e: if Gmail is used, the connection can continue reading until the word “ENHANCEDSTATUSCODES\r\n” has been received and the whole process continues as a charm. But obviously this is not a practical option.
Another approach has been include this specific command in a try/catch block and use the timer to abort the reading process after a while. Some as:
// the connection-object panelp is defined here -out of the try/catch block-
try {
if (!smtpConnect (panelp)) {
// throw some error…
}
} catch (...) {
// if (error == connection timed-out) then continue
}
// the process continues here
The problem here is that if continuing after an exception, the process hang in the next asio operation. It seems as if the stack unwinding affected the asio behavior in some way.
Please see this document: SMTP Multiline Reponses: