【问题标题】:When file is sent via SMTP it lose some bytes. c++当文件通过 SMTP 发送时,它会丢失一些字节。 C++
【发布时间】:2021-01-26 16:01:20
【问题描述】:

我正在尝试通过 SMTP 发送电子邮件,我发送多部分邮件,包含文本部分和应用程序/八位字节流部分。当我尝试发送非 *.txt" 文件时,例如 .jpg 或 .docx,它已损坏并且丢失了一些字节。例如,当我尝试发送文件 123.docx 时,此文件的大小为 166 020 字节. 我在电子邮件中收到文件,但它只有 166 006,我无法打开它。变量“total”显示发送的字节数正确。 我的代码如下:

#include <windows.h>
#include <winsock.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
using namespace std;


int fileSize(char fileName[])
{
    std::streampos fsize = 0;

    std::ifstream myfile (fileName, ios::in);  // File is of type const char*

    fsize = myfile.tellg();         // The file pointer is currently at the beginning
    myfile.seekg(0, ios::end);      // Place the file pointer at the end of file

    fsize = myfile.tellg() - fsize;
    myfile.close();

    cout << "size is: " << fsize << " bytes.\n";
    return fsize;
}

int main() {
char text[2048];
//connecting to smtp server

    //sending DATA
    strcpy(text,"DATA\n");
    send(s,text,strlen(text),0);

    recv(s,text,sizeof(text),0);
    cout<<"recv - "<<text<<endl;

    //FROM field
    strcpy(text,"FROM: laboratory4_mm@rambler.ru\n");
    send(s,text,strlen(text),0);
    
    //TO field
    strcpy(text,"TO: ");
    strcat(text,reciever);
    strcat(text,"\n");
    send(s,text,strlen(text),0);

    // SUBJECT field 
    char subject[2048];
    cout<<"Enter the theme of the letter"<<endl;
    cin.getline(subject,2048);
    strcpy(text,"SUBJECT: ");
    strcat(text,subject);
    strcat(text,"\n");
    send(s,text,strlen(text),0);

    // delimeter of multipart message
    strcpy(text,"Content-Type: multipart/mixed; boundary=\"---nsabnqeaSA43ds2\"\n");
    send(s,text,strlen(text),0);

    //Text part
    strcpy(text,"-----nsabnqeaSA43ds2\nContent-Type: text/plain; charset=utf8\nContent-Transfer-Encoding: 8bit\n\n");
    send(s,text,strlen(text),0);

    cout<<"Enter the text:"<<endl;
    cin.getline(text,2048);
    send(s,text,strlen(text),0);

    //File part
    char fileName[256];
    cout<<"Enter file name: ";
    cin.getline(fileName,255);
    int size = fileSize(fileName);
    char fileLength[1024];
    itoa(size,fileLength,10);
    cout<<fileLength<<endl;
    strcpy(text,"\n-----nsabnqeaSA43ds2 \nContent-Type: application/octet-stream\nContent-Length: ");
    strcat(text,fileLength);
    strcat(text,"\nContent-Transfer-Encoding: binary\nContent-Disposition: attachment;\n\n");
    send(s,text,strlen(text),0);
    
    ifstream fin;
    fin.open(fileName,ios::binary);
    char *buf = new char[1024];
    int readBytes;
    int total =0;
    while((readBytes = fin.read(buf,1024).gcount())>0) {
         int sent= send(s,buf,readBytes,0);
         total+=sent;
         delete buf;
         buf = new char[1024];
    }
    fin.close();
    delete buf;
    cout<< total<<endl;

    strcpy(text,"\n-----nsabnqeaSA43ds2--\n");
    send(s,text,strlen(text),0);

// telling that DATA is over
    strcpy(text,"\n.\n");
    send(s,text,strlen(text),0);
    fout<<text;
    recv(s,text,sizeof(text),0);
    cout<<"recv - "<<text<<endl;

//Disconnecting from server
return 0;
}

【问题讨论】:

  • 您需要检查返回值和 errno 以更好地了解正在发生的事情。
  • 我添加了这一行来检查是否发送了所有字节if(sent!=readBytes) cout&lt;&lt;"ERROR"&lt;&lt;endl;。我也制作了输出流来从输入文件复制数据,这个副本没问题,它有所有字节。
  • 难道你不应该对通过 MIME 发送的二进制数据进行 base64 编码吗?
  • 如果我说“内容传输编码:二进制”我还需要对文件进行编码吗?
  • 您的fileSize 函数以文本模式而不是二进制模式打开文件。因此,它会将 CRLF 对误计为单个字符。

标签: c++ smtp file-transfer windows-socket-api


【解决方案1】:

在 MIME 编码中有几个基本错误,这里:

首先,空行应该将标题与内容分开。空行不见了:

strcpy(text,"Content-Type: multipart/mixed; boundary=\"---nsabnqeaSA43ds2\"\n");

这里生成一个换行符。

strcpy(text,"-----nsabnqeaSA43ds2\nContent-Type: text/plain; charset=utf8\nContent-Transfer-Encoding: 8bit\n\n");

邮件内容从这里开始,前面没有空行。

此外,边界分隔符之前的换行符是边界分隔符的逻辑部分,因此也缺少换行符。有关详细信息,请参阅 MIME 文档。

strcpy(text,"\n-----nsabnqeaSA43ds2 \nContent-Type: application/octet-stream\nContent-Length: ");

请注意,这里您在边界分隔符之前显式发送换行符,因此您必须了解此要求。

其次:

while((readBytes = fin.read(buf,1024).gcount())>0) {
     int sent= send(s,buf,readBytes,0);

按原样发送二进制文件的内容?那不会飞的。尽管它可能是正确的 MIME 编码,也可能不是正确的 MIME 编码,但 SMTP 仍然是基于纯文本的传输协议。有一个传输二进制数据的扩展,但显示的代码没有使用它。

按原样,这是未定义行为的 SMTP 版本。没有保证的结果。如果您需要可靠地附加此文件,则必须对其进行 base64 编码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-05
    相关资源
    最近更新 更多