2

I know there are similar questions but I still cant get this to work or understand what i am supposed to do.

Im writing an application in C++ and using QtCreator. I am trying to use the SendGrid web api to send an email with an html file attached. so far I have been able to send an email but I am having trouble attaching a file to it (the file is local). The documentation says:

The file contents must be part of the multipart HTTP POST. Ex: files[file1.jpg]=file1.jpg&files[file2.pdf]=file2.pdf'

I wasn't exactly sure what is meant by this so i researched what a multipart http post was and saw examples but i cant see how i would get it to work with what I am doing. so far all I have needed to do is call post, enter the link for the request and the post data:

api_user=your_sendgrid_username&api_key=your_sendgrid_password&to=destination@example.com&toname=Destination&subject=Example_Subject&text=testingtextbody&from=info@domain.com

I don't see where a multipart HTTP post would come into this and how it could replace the current post data, Ive seen things like setting the Header and Body in a multipart HTTP post but i don't see how any of that is relevant to what i am doing or what i am supposed to do with it.

Could someone please give me an example of how I could attach a local file to the post call to SendGrid in Qt C++

Update: This is my interpretation of justin steele's instructions:

 char speechMk = '"';
QString boundary = "----------------------------123456789abc";
    QByteArray data(QString("--" + boundary + "\r\n").toLatin1());
    data.append(QString("Content-Disposition: form-data; name=" + QString(speechMk) + "api_user" + QString(speechMk) + "\r\n").toLatin1());
       data.append("myuser");
       data.append("\r\n");

       data.append("--" + boundary + "\r\n");
       data.append("Content-Disposition: form-data; name=" + QString(speechMk) + "api_key" + QString(speechMk) + "\r\n" );
       data.append("mypassword");
       data.append("\r\n");

       data.append("--" + boundary + "\r\n");
       data.append("Content-Disposition: form-data; name=" + QString(speechMk) + "to" + QString(speechMk) + "\r\n");
       data.append("myemail@hotmail.co.uk");
       data.append("\r\n");

        data.append("--" + boundary + "\r\n");
       data.append("Content-Disposition: form-data; name=" + QString(speechMk) + "toname" + QString(speechMk) + "\r\n");
       data.append( "Destination");
       data.append("\r\n");

       data.append("--" + boundary + "\r\n");
       data.append("Content-Disposition: form-data; name=" + QString(speechMk) + "subject" + QString(speechMk) + "\r\n");
       data.append("eSubject");
       data.append("\r\n");

       data.append("--" + boundary + "\r\n");
       data.append("Content-Disposition: form-data; name=" + QString(speechMk) + "text" + QString(speechMk) + "\r\n");
       data.append("eBody");
       data.append("\r\n");

       data.append("--" + boundary + "\r\n");
      data.append("Content-Disposition: form-data; name=" + QString(speechMk) + "from" + QString(speechMk) + "\r\n");
      data.append("noreply@randomdomain.com");
      data.append("\r\n");

      data.append("--" + boundary + "\r\n");
      data.append("Content-Disposition: form-data; name=" +  QString(speechMk) + "files[1]" + QString(speechMk) + "; filename=" + QString(speechMk) + "TodayRoute.html" + QString(speechMk) + "\r\n");

      data.append("Content-Type: application/octet-stream");
      data.append("\r\n");
      QFile file1(path);
      if (!file1.open(QFile::ReadOnly)){
          qDebug() << "could not open";
      } else {
          data.append(file1.readAll().toBase64() + "\r\n");
      }
      data.append("--" + boundary + "\r\n");

    file1.close();

    QNetworkAccessManager theMan;

    QNetworkRequest req = QNetworkRequest(QUrl("https://api.sendgrid.com/api/mail.send.json"));
    req.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("multipart/form-data; boundary=" + boundary));
    theMan.post(req,data);

This is what i had before (below) and it would send an email with an attached file, but the attached file wouldn't contain the contents I wanted.

 QByteArray data(QString("api_user=myuser&").toLatin1());
        data.append("api_key=mypassword&");
        data.append("to=myemail@hotmail.co.uk&");
        data.append("toname=Destination&");
        data.append("files[TodayRoute.html]=");
        QFile file(path);
            if (!file.open(QIODevice::ReadOnly)){
                qDebug() << "QFile Error: File not found!";
            //    return data;
            } else { qDebug() << "File found, proceed as planned"; }
        data.append(file.readAll());

        data.append("&subject=Example_Subject&");
        data.append("text=testingtextbody&");
        data.append("from=noreply@domainrandom.com");



           QUrl mResultsURL = QUrl("https://api.sendgrid.com/api/mail.send.json");
           QNetworkAccessManager mNetworkManager;
           QNetworkRequest request(mResultsURL); //our server with php-script
          mNetworkManager.post(request,data);
        file.close(); 
user2471711
  • 85
  • 1
  • 8
  • If you can "translate" VBA to your language see my answer to [http://stackoverflow.com/questions/35423101/sendgrid-attachments-are-empty-or-corrupt-using-api-vba](http://stackoverflow.com/questions/35423101/sendgrid-attachments-are-empty-or-corrupt-using-api-vba) – Justin Steele Mar 02 '16 at 22:59
  • Where you see BASE64ENCODEDFILE in that example you would replace that with the Base64 encoded file (read it from disk, base64 encode it). To add more files you'd add: dataToSend = dataToSend + "--" + boundary + vbCrLf dataToSend = dataToSend + "Content-Disposition: form-data; name=""files[2]""; filename=""my2ndPDF.pdf""" + vbCrLf dataToSend = dataToSend + "Content-Type: application/octet-stream" + vbCrLf dataToSend = dataToSend + 2NDBASE64ENCODEDFILE + vbCrLf dataToSend = dataToSend + "--" + boundary + vbCrLf – Justin Steele Mar 02 '16 at 23:03
  • Post some code so we'll see what you are trying. Here is an example how to attach a file and set header for multipart with QNAM http://stackoverflow.com/questions/15109656/qnetworkaccessmanager-post-http-multipart-from-serial-qiodevice – misha130 Mar 03 '16 at 15:03
  • @JustinSteele Ive written what i think should be the equivalent to your code in C++ but its not sending emails. – user2471711 Mar 03 '16 at 16:50
  • @misha130 i have posted what i have been trying, the multipart request on the page you linked is what i am confused about, how could i get that to work with what i currently have? on the send grid web api it didn't mention things like 'Content Type Headers' so I'm not sure where or why it would come into the code i currently have – user2471711 Mar 03 '16 at 22:25
  • No No it did mention that https://sendgrid.com/docs/API_Reference/Web_API/mail.html#-send see example in the end. Basically your POST should look like theirs. If all fails, include curl and let it handle it for you. But I mean if everything everything fails. – misha130 Mar 03 '16 at 22:34
  • ah ok, so I should replicate this format in my post request from the point "Content-Type: multipart/form-data...." up until "HTTP/1.1 200 OK" ? – user2471711 Mar 03 '16 at 22:40
  • I figured it out! Posting answer soon... – Justin Steele Mar 04 '16 at 00:17

1 Answers1

2

I played around with this using C# and learned that you need an empty line "\r\n" between the Content-Disposition: line and the value. I believe you also need one after the Content-Type: line for the file. And the last boundary ends with '--'.

    char speechMk = '"';
    QString boundary = "----------------------------123456789abc";

    QByteArray data(QString("--" + boundary + "\r\n").toLatin1());

    data.append(QString("Content-Disposition: form-data; name=" + QString(speechMk) + "api_user" + QString(speechMk) + "\r\n").toLatin1());
    data.append("\r\n");
    data.append("myuser");
    data.append("\r\n");

    data.append("--" + boundary + "\r\n");
    data.append("Content-Disposition: form-data; name=" + QString(speechMk) + "api_key" + QString(speechMk) + "\r\n" );
    data.append("\r\n");
    data.append("mypassword");
    data.append("\r\n");

    data.append("--" + boundary + "\r\n");
    data.append("Content-Disposition: form-data; name=" + QString(speechMk) + "to" + QString(speechMk) + "\r\n");
    data.append("\r\n");
    data.append("myemail@hotmail.co.uk");
    data.append("\r\n");

    data.append("--" + boundary + "\r\n");
    data.append("Content-Disposition: form-data; name=" + QString(speechMk) + "toname" + QString(speechMk) + "\r\n");
    data.append("\r\n");
    data.append( "Destination");
    data.append("\r\n");

    data.append("--" + boundary + "\r\n");
    data.append("Content-Disposition: form-data; name=" + QString(speechMk) + "subject" + QString(speechMk) + "\r\n");
    data.append("\r\n");
    data.append("eSubject");
    data.append("\r\n");

    data.append("--" + boundary + "\r\n");
    data.append("Content-Disposition: form-data; name=" + QString(speechMk) + "text" + QString(speechMk) + "\r\n");
    data.append("\r\n");
    data.append("eBody");
    data.append("\r\n");

    data.append("--" + boundary + "\r\n");
    data.append("Content-Disposition: form-data; name=" + QString(speechMk) + "from" + QString(speechMk) + "\r\n");
    data.append("\r\n");
    data.append("noreply@randomdomain.com");
    data.append("\r\n");

    data.append("--" + boundary + "\r\n");
    data.append("Content-Disposition: form-data; name=" +  QString(speechMk) + "files[1]" + QString(speechMk) + "; filename=" + QString(speechMk) + "TodayRoute.html" + QString(speechMk) + "\r\n");

    data.append("Content-Type: application/octet-stream");
    data.append("\r\n");
    data.append("\r\n");

    QFile file1(path);
    if (!file1.open(QFile::ReadOnly)){
        qDebug() << "could not open";
    } else {
        data.append(file1.readAll().toBase64() + "\r\n");
    }
    data.append("--" + boundary + "--\r\n");

    file1.close();

    QNetworkAccessManager theMan;

    QNetworkRequest req = QNetworkRequest(QUrl("https://api.sendgrid.com/api/mail.send.json"));
    req.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("multipart/form-data; boundary=" + boundary));
    theMan.post(req,data);
Justin Steele
  • 2,230
  • 13
  • 16
  • thanks so much, this worked! although it did require two small changes, i renamed 'files[1]' to 'files[TodayRoute.html]' and i removed the '.toBase64()' from the 'file1.readAll()' – user2471711 Mar 04 '16 at 01:05