连接到奇怪的SMTP服务器

时间:2014-06-10 15:27:49

标签: c sockets email smtp

我已经编写了一个代码,它基本上连接到每个可用的SMTP服务器,除了1.问题是,服务器在多个框架中发送一些消息,例如:

C: EHLO domain

S: 220 smtp.horribleserver.com welcome ESMTP  <-- 1 frame
S: 250-STARTTLS                               <-- 1 frame
   250-AUTH LOGIN PLAIN
   250-AUTH=LOGIN PLAIN
   250-SIZE 120000000
   250 HELP

C: STARTTLS

S: STARTTLS ready
S: 250-AUTH LOGIN PLAIN                       <-- 1 frame
S: 250-AUTH=LOGIN PLAIN                       <-- 1 frame
S: 250-SIZE 120000000                         <-- 1 frame
S: 250 HELP                                   <-- 1 frame

我尝试重写接收函数来处理多个帧回复:

int ReceiveData()
{
    int res, i = 0;
    fd_set fdread;
    timeval time;
    int s = 1;
    int iCurrentSize = 0;
    time.tv_sec = 5;
    time.tv_usec = 0;
    char cBuffer[1024] = "";
    if (RecvBuf == NULL)
    {
        return -1;
    }
    memset(RecvBuf, 0, BUFFER_SIZE);

    while (1)
    {
        FD_ZERO(&fdread);
        FD_SET(hSocket, &fdread);
        if ((res = select(hSocket + 1, &fdread, NULL, NULL, &time)) == SOCKET_ERROR)
        {
            FD_CLR(hSocket, &fdread);
            return -1;
        }
        if (res == 0)
        {
            //timeout
            printf("S: %s\n", RecvBuf);
            FD_CLR(hSocket, &fdread);
            return (iCurrentSize + 1);
        }
        if (FD_ISSET(hSocket, &fdread))
        {
            s = recv(hSocket, cBuffer, sizeof(cBuffer), 0);
            if (s < 0)
            {
                FD_CLR(hSocket, &fdread);
                return -1;
            }
            if (iCurrentSize >= BUFFER_SIZE)
            {
                return -2;
            }
            memcpy(&RecvBuf[iCurrentSize], cBuffer, s);
            iCurrentSize += s;
        }
    }
}

RecvBuffer指向大小为BUFFER_SIZE的堆上的内存。

我已经尝试了超过30秒的超时,但结果总是一样的:

S: 220 smtp.horribleserver.com welcome ESMTP  
S: 250-STARTTLS                               
   250-AUTH LOGIN PLAIN
   250-AUTH=LOGIN PLAIN
   250-SIZE 120000000
   250 HELP

我期待得到以下内容:

S: 220 smtp.horribleserver.com welcome ESMTP  
   250-STARTTLS                               
   250-AUTH LOGIN PLAIN
   250-AUTH=LOGIN PLAIN
   250-SIZE 120000000
   250 HELP

即。一旦超时发生,所有回复都存储在同一个缓冲区中。

知道为什么我的代码没有返回预期的结果吗?

1 个答案:

答案 0 :(得分:0)

虽然已在评论中回答,但我会为完整性添加一个答案,但是对于窃取答案感觉有点不好,所以会尽可能地添加它。

对于SMTP,您将连接到端口,然后逐行读取套接字,因此编写ReadLine函数将数据作为字符串返回将是第一步。这个函数只是逐字节读取,直到找到\ r \ n(回车/换行)字节组合。

在初始连接时,您将读取每一行,直到您得到一行包含“220”表示服务器就绪 - 请注意空格,因为服务器就绪横幅(以及后续回复)可以通过在代码后面加一个连字符来实现多行。 所以你可以有像

这样的东西
220-xxx
220 Server Ready - this is the end of the reply

您现在发送握手的“EHLO”部分希望获得250回复,因此逐行读取,直到回复行以“250”开头 - 再次注意到该空间,尽管您会注意到,但通常会得到一个“250 START”你会经常收到一堆以“250-”开头的行,然后是250之后的最后一行空间

雅虎邮件服务器目前为我们提供了一个很好的例子:

220 mta1262.mail.bf1.yahoo.com ESMTP ready
250-mta1262.mail.bf1.yahoo.com
250-PIPELINING
250-SIZE 41943040
250-8BITMIME
250 STARTTLS

250 STARTTLS是答复的结尾。

如上所述,这是RFC 5321规范的全部内容。

虽然OP不再需要此解决方案,但我希望它对其他人有帮助。