tags:

views:

81

answers:

2

I am trying to create a simple send mail function for a custom app created with the Qt framework in C++. I am very close just at the point where SMTP is trying to authenticate and can't for the life of me to get this to work. Here is what I am working with

do {
    responseLine = socket->readLine();
    response += responseLine;
}
while ( socket->canReadLine() && responseLine[3] != ' ' );
    responseLine.truncate( 3 );
if ( state == Init && responseLine[0] == '2' ) {
    // banner was okay, let's go on
    *t << "HELO there\r\n";
    t->flush();
    state = Auth;
} else if (state == Auth && responseLine[0] == '2') {
    *t << "STARTTLS\r\n";
    *t << "AUTH PLAIN\r\n";
    t->flush();
    state = User;
} else if (state == User && responseLine[0] == '2') {
    *t << "username\r\n";
    t->flush();
    state = Pass;
} else if (state == Pass && responseLine[0] == '2') {
    *t << "pass\r\n";
    t->flush();
    state = Mail;
} else if ( state == Mail && responseLine[0] == '2' ) {
    // HELO response was okay (well, it has to be)
    *t << "MAIL FROM: " << from << "\r\n";
            t->flush();
    state = Rcpt;
} else if ( state == Rcpt && responseLine[0] == '2' ) {
    *t << "RCPT TO: " << rcpt << "\r\n"; //r
            t->flush();
    state = Data;
} else if ( state == Data && responseLine[0] == '2' ) {
    *t << "DATA\r\n";
            t->flush();
    state = Body;
} else if ( state == Body && responseLine[0] == '3' ) {
    *t << message << "\r\n.\r\n";
            t->flush();
    state = Quit;
} else if ( state == Quit && responseLine[0] == '2' ) {
    *t << "QUIT\r\n";
            t->flush();
    // here, we just close.
    state = Close;
    emit status( tr( "Message sent" ) );
} else if ( state == Close ) {
    deleteLater();
    return;
} else {
    // something broke.
+1  A: 

Is it an encryption problem? I can see you're using STARTTLS, but I cannot see how you handle the actual en-/decryption of the subsequent lines...

According to RFC 2595, encryption must start immediately after the OK response to the STARTTLS command. Your code suggests that you do not even wait for that OK, instead you send AUTH PLAIN immediately, resulting in plain text continuation from your client while the server expects encryption.

Edit: If you don't need encryption, just leave out STARTTLS and stick to the (E)SMTP standard as defined in the RFCs ... For ESMTP Auth you may need to use EHLO instead of HELO, else the server may not understand AUTH.

You'll find all SMTP-related RFCs on the corresponding Wikipedia page. Most notably, you'll need RFC5321 (most recent summary of SMTP) and RFC4954 (most recent description of ESMTP AUTH). But ... it may be more complicated than you think. There may be some SMTP servers that do not accept AUTH PLAIN when the connection is not encrypted. You'd need to evaluate the server's response to the EHLO command (see the example section in RFC4954).

I think it would be easier for you to just use a library. I do not know one for C++, you need to find it by yourself.

maligree
i don't need encryption, how would I authenticate using plain text username/password
rizzo0917
I just added some information about SMTP RFCs ...
maligree
+1  A: 

You're using a QTextStream? That seems wrong. QTextStream is for writing encoded text and will mess with both encoding and line endings and that's not what you want when implementing a protocol. Better use QByteArray (instead of QString) and QDataStream instead of QTextStream, or for better error handling, write directly to the socket.

Frank