Issue with Attachment in Sugar v 10 using HttpWebResponse

I m facing issue uploading files/Attachments to Sugar CRM using HttpWebRequest Sugar v10. Everytime i POST an attachment, it is giving me "Attachment is missing". Please help.

  • Posting an attachment could mean several things.  Uploading a file as a Note.  Uploading a file as a Document.  Attaching a file to an email.

    To upload a file as a Note,  Insert or Update a Note and pass the file as Binary to the attachment "field".

    To attache a file to an email, it's more difficult.  See response below from Sugar Support:
    My first piece of advice for working with the Sugar v10-v11 REST API is to take advantage of the fact that the browser UI leverages the same UI that your app will. Often times, when looking for an idea of how to achieve something with the API, enabling your favorite browser's developer tools and turning on the Network view, then taking the same action (like creating a temp file, etc) in the browser will reveal how Sugar's browser client (in javascript) sends a similar request.

    In regards to the Temp File endpoint and the potential for confusion in the API documentation, as originally cited at:

    http://support.sugarcrm.com/Documentation/Sugar_Developer/Sugar_Developer_Guide_7.11/Integration/Web_Services/v10_-_v11/v11/Endpoints/moduletempfilefield_POST/

    One primary issue with the above article is that it implies that the Request data should be sent to the above endpoint as a JSON object. This is incorrect (and I will work with our developer team to ensure that this gets corrected both in the built-in documentation for the product and in our public-facing documentation above). If you look at our example on how to send file attachments to the API at : 

    http://support.sugarcrm.com/Documentation/Sugar_Developer/Sugar_Developer_Guide_7.11/Integration/Web_Services/v10_-_v11/v11/Examples/PHP/How_to_Manipulate_File_Attachments/

    You'll notice the line in the code comments:

    //Do NOT set Content Type Header to JSON

    The request should be sent as a normal POST request, with the file set as a POST parameter with the name as 'filename' (or whatever the fieldname is that is of type "file" that you are wanting to upload).

    To your specific question about the Module to create the Temp file against, in actuality, it probably doesn't matter, since it is a Temp file, but to be consistent with how the browser does it, and also with what the attachment will eventually be for the Email record, the attachment temp file should be of the module Notes (because for Emails, the attachments are just related Note records having a file attached to each). So with that in mind, the temp file endpoint to use for uploading the attachment would be:

    /Notes/temp/file/filename

    with the Post parameters as :

    format: "sugar-html-json"
    delete_if_fails:true
    filename:"@/path/to/file.ext"

    In the case of how to set the filename parameter to an actual file, this is going to depend on your HTTP framework (and environment), but it would not be base64 encoded, it would simply be a normal File upload (as far as HTTP is concerned). Looking at your example code, it seems like you are using the RestSharp. I'm not personally well-versed in this library (or C#, or Windows development), but based on various documentation sources, and cannibalizing from your example and other examples online, a rough idea of what the request might look like is:

    var request = new RestRequest("Notes/temp/file/filename", Method.POST);

    request.AddHeader("OAuth-Token", sessionid);

    request.AddParameter("format", "sugar-html-json");
    request.AddParameter("delete_if_fails", true);

    request.AddFile("filename", "C:\Code\Visual Studio\Starfish\Logo\starfish_logo_transparent.png");

    RestResponse response = (RestResponse)ExecREST(request);


    Again, I haven't used this framework before, and the above is not tested. I simply looked online for how to set parameters, files, and headers via RestSharp library and plugged in your example parts.

    Some examples show us setting both oauth-token as a header and as a parameter, others don't. I would personally try it with just the header first, and if necessary, add it as a parameter.

    The response will look something like:

    {
    "filename": {
    "guid": "test_file.txt"
    },
    "record": {
    "id": "06e4e97e-3c13-11e8-8bd1-3c15c2c511e8",
    "deleted": false,
    "file_mime_type": "text/plain",
    "file_ext": "txt",
    "file_size": 1444,
    "filename": "test_file.txt",
    "portal_flag": false,
    "embed_flag": false,
    "my_favorite": false,
    "_acl": {
    "fields": {}
    },
    "_module": "Notes"
    }
    }

    (note that I did a fair amount of cleaning up of the actual response to make it more clear which parts are worth noting).

    Again, if you were to go to Emails > Compose Email in a desktop browser (with developer tools and network logging enabled), you would see the above when uploading an attachment to the Compose Email view. If, at that point,you were to choose to "Save as Draft" (which allows saving the Email record without most of the otherwise-required fields and system settings filled out), the POST request is sent to the following API endpoint:

    /Emails

    with the JSON body of the request having, amongst other standard parts, the following section:

    "attachments": {
    "create": [
    {
    "_link": "attachments",
    "filename_guid": "06e4e97e-3c13-11e8-8bd1-3c15c2c511e8",
    "name": "test_file.txt",
    "filename": "test_file.txt",
    "file_mime_type": "text/plain",
    "file_size": 1444,
    "file_ext": "txt",
    "deleted": false,
    "portal_flag": false,
    "embed_flag": false
    }
    ],
    "add": [],
    "delete": []
    },

    So that the object inside the attachments.create array looks the same as the "record" object returned from the Temp File response, in terms of which fields match up from one to the other. Eg :

    "attachments": {
    "create": [
    {
    "_link": "attachments",
    "filename": Temp.record.filename,
    "file_mime_type": Temp.record.file_mime_type,
    "file_size": Temp.record.file_size,
    "file_ext": Temp.record.file_ext,
    "deleted": Temp.record.deleted,
    "portal_flag": Temp.record.portal_flag,
    "embed_flag": Temp.record.embed_flag
    }
    ]
    },

    (with Temp.record understood in this example to be the "record" object part of response JSON returned by the temp/file request). The two fields that aren't an exact 1:1 match are:

    "filename_guid"
    "name":

    For these, "name" will generally match "filename", and "filename_guid" will match the temp record's ID. So with that in mind, the above could be expressed as:

    "attachments": {
    "create": [
    {
    "_link": "attachments",
    "filename_guid": Temp.record.id,
    "name": Temp.record.filename,
    "filename": Temp.record.filename,
    "file_mime_type": Temp.record.file_mime_type,
    "file_size": Temp.record.file_size,
    "file_ext": Temp.record.file_ext,
    "deleted": Temp.record.deleted,
    "portal_flag": Temp.record.portal_flag,
    "embed_flag": Temp.record.embed_flag
    }
    ],
    "add": [],
    "delete": []
    },

    This would be what you would add to the main Email object that you were sending to the /Emails API to create the attachments at the same point that the Email record is created, as documented at:

    http://support.sugarcrm.com/Documentation/Sugar_Developer/Sugar_Developer_Guide_7.11/Integration/Web_Services/v10_-_v11/v11/Endpoints/Emails_POST/