繁体   English   中英

使用c ++发送smtp邮件

[英]Using c++ to send smtp mail

我想知道你是否能帮我理解这里出了什么问题。 我正在尝试编写一个在端口25上进行SMTP对话的小客户端。

如果您回想起SMTP,您需要发送一些内容,然后在DATA消息之后编写电子邮件,在其自己的行上以句点结束以发送电子邮件。

程序处理这个问题的方式存在问题。 它处理对话,直到DATA消息之后。 只有当我先输入它时才能识别周期。 在任何后续行之后,任何代码执行似乎都会丢失。 if语句无法识别是否已输入句点。 再次感谢你。 附件是相关代码..

void readstuff(int sock, char* buf) {
    int r = read (sock, buf, BUFSIZE -1);
    buf[r] = NULL;
    cout << buf << endl;
}

void doit(int sock, string arg, char* buf) {
    int r = write(sock, arg.c_str(), arg.length());
    readstuff(sock, buf);
}

int main(int argc, char *argv[]) {
    char buf[BUFSIZE];

    // Make a socket
    int sock = MakeSocket(argv[1], argv[2]);
    cout << "socket is " << sock << endl;
    assert(sock != -1);

    // Begin dialogue
    doit(sock, "HELO " + org.substr(org.find("@") + 1) + "\r\n", buf);
    doit(sock, "MAIL FROM: <" + org + "> \r\n", buf);
    doit(sock, "RCPT TO: <" + dest + "> \r\n", buf);
    doit(sock, "DATA \r\n", buf);
    readstuff(sock, buf);  //should say "go ahead"

    //User writes email here      
    while (true) {              
        string line = "";
        getline(cin, line);
        doit(sock, line + "\r\n", buf);
        if (line == ".") {
            readstuff(sock, buf); //should say "email cleared to send"
            return 0;
        }
    }
}

请阅读SMTP规范RFC 5321 ,特别是4.1.1.4 DATA4.5.2透明度部分

4.1.1.4.  DATA (DATA)

   The receiver normally sends a 354 response to DATA, and then treats
   the lines (strings ending in <CRLF> sequences, as described in
   Section 2.3.7) following the command as mail data from the sender.
   This command causes the mail data to be appended to the mail data
   buffer.  The mail data may contain any of the 128 ASCII character
   codes, although experience has indicated that use of control
   characters other than SP, HT, CR, and LF may cause problems and
   SHOULD be avoided when possible.

   The mail data are terminated by a line containing only a period, that
   is, the character sequence "<CRLF>.<CRLF>", where the first <CRLF> is
   actually the terminator of the previous line (see Section 4.5.2).
   This is the end of mail data indication.  The first <CRLF> of this
   terminating sequence is also the <CRLF> that ends the final line of
   the data (message text) or, if there was no mail data, ends the DATA
   command itself (the "no mail data" case does not conform to this
   specification since it would require that neither the trace header
   fields required by this specification nor the message header section
   required by RFC 5322 [4] be transmitted).  An extra <CRLF> MUST NOT
   be added, as that would cause an empty line to be added to the
   message.  The only exception to this rule would arise if the message
   body were passed to the originating SMTP-sender with a final "line"
   that did not end in <CRLF>; in that case, the originating SMTP system
   MUST either reject the message as invalid or add <CRLF> in order to
   have the receiving SMTP server recognize the "end of data" condition.

   The custom of accepting lines ending only in <LF>, as a concession to
   non-conforming behavior on the part of some UNIX systems, has proven
   to cause more interoperability problems than it solves, and SMTP
   server systems MUST NOT do this, even in the name of improved
   robustness.  In particular, the sequence "<LF>.<LF>" (bare line
   feeds, without carriage returns) MUST NOT be treated as equivalent to
   <CRLF>.<CRLF> as the end of mail data indication.

   Receipt of the end of mail data indication requires the server to
   process the stored mail transaction information.  This processing
   consumes the information in the reverse-path buffer, the forward-path
   buffer, and the mail data buffer, and on the completion of this
   command these buffers are cleared.  If the processing is successful,
   the receiver MUST send an OK reply.  If the processing fails, the
   receiver MUST send a failure reply.  The SMTP model does not allow
   for partial failures at this point: either the message is accepted by
   the server for delivery and a positive response is returned or it is
   not accepted and a failure reply is returned.  In sending a positive
   "250 OK" completion reply to the end of data indication, the receiver
   takes full responsibility for the message (see Section 6.1).  Errors
   that are diagnosed subsequently MUST be reported in a mail message,
   as discussed in Section 4.4.

   When the SMTP server accepts a message either for relaying or for
   final delivery, it inserts a trace record (also referred to
   interchangeably as a "time stamp line" or "Received" line) at the top
   of the mail data.  This trace record indicates the identity of the
   host that sent the message, the identity of the host that received
   the message (and is inserting this time stamp), and the date and time
   the message was received.  Relayed messages will have multiple time
   stamp lines.  Details for formation of these lines, including their
   syntax, is specified in Section 4.4.

   Additional discussion about the operation of the DATA command appears
   in Section 3.3.

   Syntax:

      data = "DATA" CRLF
4.5.2.  Transparency

   Without some provision for data transparency, the character sequence
   "<CRLF>.<CRLF>" ends the mail text and cannot be sent by the user.
   In general, users are not aware of such "forbidden" sequences.  To
   allow all user composed text to be transmitted transparently, the
   following procedures are used:

   o  Before sending a line of mail text, the SMTP client checks the
      first character of the line.  If it is a period, one additional
      period is inserted at the beginning of the line.

   o  When a line of mail text is received by the SMTP server, it checks
      the line.  If the line is composed of a single period, it is
      treated as the end of mail indicator.  If the first character is a
      period and there are other characters on the line, the first
      character is deleted.

   ...

您的DATA命令需要考虑到:

  • 你的doit()函数在发送字符串后期待响应。 这是在发送电子邮件数据时使用的错误逻辑。 在最终终止<CRLF>.<CRLF>之后才能读取响应<CRLF>.<CRLF>已发送。

  • 您必须将透明度应用于以a开头的电子邮件中的任何行. 字符。

话虽如此,尝试更像这样的东西:

int readLine(int sock, string &line)
{
    // read a line from sock until CRLF is reached.
    // I leave this as an exercise for you to implement...

    line = ...;
    return -1 on error, else 0;
}

int readResponse(int sock)
{
    // Please read RFC 5321 section 4.2 for the PROPER format
    // of an SMTP response.  You should be reading from the
    // socket until you receive the terminating
    // "Reply-code [ SP textstring ] CRLF" line...

    string line;

    int r = readLine(sock, line);
    if (r < 0) return r;

    string code = line.substr(0, 3);
    string text = line.substr(4);

    if ((line.length() >= 4) && (line[3] = '-'))
    {
        do
        {
            r = readLine(sock, line);
            if (r < 0) return r;

            text += (" " + line.substr(4));
        }
        while (line.compare(0, 4, code+"-") == 0);
    }

    cout << code << ": " << text << endl;

    return stoi(code);
}

int sendText(int sock, const string &arg)
{
    const char *p = arg.c_str();
    int len = arg.length();

    while (len > 0)
    {
        int r = write(sock, p, len);
        if (r <= 0) return -1;
        p += r;
        len -= r;
    }

    return 0;
}

int sendCmd(int sock, const string &arg)
{
    int r = sendText(sock, arg + "\r\n");
    if (r < 0) return r;
    return readResponse(sock);
}

int main(int argc, char *argv[])
{
    // Make a socket
    int sock = MakeSocket(argv[1], argv[2]);
    cout << "socket is " << sock << endl;
    assert(sock != -1);

    // Begin dialogue

    // read the server greeting first...
    if (readResponse(sock) != 220) {
        // failed, do something...
    }

    if (sendCmd(sock, "HELO " + org.substr(org.find("@") + 1)) != 250) {
        // failed, do something...
    }

    if (sendCmd(sock, "MAIL FROM: <" + org + ">") != 250) {
        // failed, do something...
    }

    int r = sendCmd(sock, "RCPT TO: <" + dest + ">");
    if ((r != 250) && (r != 251)) {
        // failed, do something...
    }

    if (sendCmd(sock, "DATA") != 354) {
        // failed, do something...
    }

    //User writes email here      
    while (true) {              
        string line;
        getline(cin, line);

        // A line consisting of only "." is a valid line in an email
        // message, so you should not use that as a terminator in your
        // input, use something else, like an EOF marker, or CTRL-C,
        // or something...
        if (some termination condition)
            break;

        // DO NOT call readResponse() here!
        if (!line.empty() && (line[0] == '.')) {
            if (sendText(sock, ".") < 0) {
                // failed, do something...
            }
        }
        if (sendText(sock, line) < 0) {
            // failed, do something...
        }
        if (sendText(sock, "\r\n") < 0) {
            // failed, do something...
        }
    }

    // NOW call readResponse() here!
    if (sendCmd(sock, ".") != 250) {
        // failed, do something...
    }

    sendCmd(sock, "QUIT");
    close(sock);

    return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM