When file is sent via SMTP it lose some bytes. c++

218 views Asked by At

i'm trying to send email via SMTP, i send multipart mail, with text part and application/octet-stream part. when i try to send not *.txt" files, for example .jpg or .docx it is got corrupted and some bytes are lost. For example, when i try to send file 123.docx, size of this file is 166 020 bytes. i recieve file in my email, but it has only 166 006 and i can't open it. Variable "total" shows correct number of bytes is sent. My code is bellow:

#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: [email protected]\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;
}

1

There are 1 answers

0
Sam Varshavchik On

There are several fundamental bugs in the MIME encoding, here:

First, a blank line is supposed to separate headers from content. The blank line is missing:

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

One newline generated here.

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

Mail content begins here, without a preceding blank line.

Additionally, the newline that precedes a boundary delimiter is a logical part of the boundary delimiter, so that newline is missing as well. See MIME documentation for more information.

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

Note that here you are explicitly sending a newline before the boundary delimiter, so you must be aware of this requirement.

Secondly:

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

Sending the contents of the binary file, as is? That's not going to fly. Even though it may or may not be correct MIME encoding, SMTP is still a plain text-based transmission protocol. There is an extension for transmission of binary data, but the shown code does not use it.

As is, this is the SMTP version of undefined behavior. No guaranteed results. If you need to attach this file reliably, you must base64-encode it.