Question
Josh Barney · Mar 24, 2016

Help with Mime attachment HTTP post request

I believe the I have followed the instructions to attach a document to the body of a post request but nothing is being sent out in the files{} port of the request.  I can either get the stream in "data", not visible at all, or visible but no form data. Any help would be appreciated, below is what I have:

ClassMethod SendFax(phone As %Stringcoverpath As %Stringdocpath As %StringAs %String
{
     Set req ##class(%Net.HttpRequest).%New()
    //test server
    Set req.Server "httpbin.org"
    Set req.SSLConfiguration "CardChoice"
    
    Do req.InsertFormData("Username",##class(HData.SiteSettings).GetFaxLogin())
    Do req.InsertFormData("Password",##class(HData.SiteSettings).GetFaxPassword())
    Do req.InsertFormData("ProductId",##class(HData.SiteSettings).GetFaxProductId())
        Do req.InsertFormData("cookies","false")
    Do req.InsertFormData("header","header")
      
    //Create job name for fax
    Set sendDate = +$H
    Set sendTime = $P($ZTIMESTAMP,",",2)+(15*60)
    Set schedDate = $ZDATETIME(sendDate_","_sendTime,1,4)
    Set schedDate = $E(schedDate,1,16)_" "_$E(schedDate,17,18)
    Set docList = $LFS(docpath,"\")
    Set docName = $LISTGET(docList,$LL(docList))
    Do req.InsertFormData("JobName",schedDate_docName)
    
    //format phone number and set billing code
    Set num = $REPLACE(phone,"-","")
    Do req.InsertFormData("BillingCode",num)
    Do req.InsertFormData("Numbers1",num)
   
    
    //get notification email
    Set email = ##class(HData.SiteSettings).GetFaxNotifyEmail()
    If (email '= "") Do req.InsertFormData("FeedbackEmail",email)
    
     // Create a new MIME message into which we'll insert
    // one or more MIME parts
    Set mimeMsg = ##class(%Net.MIMEPart).%New()

    // Create the MIME part
    Set mimePart = ##class(%Net.MIMEPart).%New()

    // The body of the part is the file stream
    Set docStream=##class(%FileBinaryStream).%New()
    &js<alert("#(docpath)#")>
    Set docStream.Filename = docpath
    Do docStream.LinkToFile(docpath)
    Set base64 = ##class(%SYSTEM.Encryption).Base64Encode(docStream)
    
    Do mimePart.BodySet(docStream)
    //Set mimePart.Body = base64
    
    // Note: ContentTransferEncoding must be explicitly set to something or
    // an error is generated. Can set it to an empty string.
    //Set mimePart.ContentTransferEncoding = "quoted-printable"
    //Set mimePart.ContentTransferEncoding = "base64"

    //Set the Content Type
    Set mimePart.ContentType = "application/pdf"

    // Add any custom headers
    //Do mimePart.SetHeader("Content-Disposition","attachment; name=""Files1""; filename="""_docName_"""")

    // Insert the part into the MIME message
    Set sc = mimeMsg.Parts.Insert(mimePart)
    Quit:$System.Status.IsError(sc)
    Set mimeMsg.ContentType = "multipart/form-data"
    Do mimeMsg.SetHeader("Content-Disposition","attachment; name=""Files1""; filename="""_docName_"""")
    Set mimeMsg.ContentTransferEncoding = "base64"

    // Create a MIME writer to output the MIME message
    Set mimeWriter = ##class(%Net.MIMEWriter).%New()
    Set sc = mimeWriter.OutputToStream(req.EntityBody)
    Quit:$System.Status.IsError(sc)

    Set sc = mimeWriter.WriteMIMEBody(mimeMsg)
    Quit:$System.Status.IsError(sc)

    // Store the output from the MIME writer in the EntityBody of the request
    //Set req.EntityBody = stream

    // Force the content type of the message to be multipart form data
    // NOTE: By default the ContentType comes from the EntityBody
    // so to explicitly set this, it must happen AFTER setting the EntityBody
    //Set req.ContentType = "multipart/form-data;boundary=" _mimeMsg.Boundary


    // Post the request
    Set err = ""
     Do req.Post("post")
    
    If '$IsObject(req.HttpResponse{
        err "Response Error"
        Quit ""
    }
    
    If '$IsObject(req.HttpResponse.Data{
        err "Data Error"
        Quit ""
    }
    
    Set response req.HttpResponse.Data.Read()
    Set ^response = response
    &js<alert("#(response)#")>
    
    Quit response

10
2 0 3 1,997
Log in or sign up to continue

I made the following changes:

1.  Changed

Set mimePart.ContentType = "application/pdf"

to

Set mimePart.ContentType = "application/x-object"

2. Commented out:

Do mimeMsg.SetHeader("Content-Disposition","attachment; name=""Files1""; filename="""_docName_"""")          
Set mimeMsg.ContentTransferEncoding = "base64"

3. Uncommented:

 //Set req.ContentType = "multipart/form-data;boundary=" _mimeMsg.Boundary

After these change I received non-empty files object.

 "files": {
              "uploadedfile": "cd \\\r\n@echo start >> date.txt\r\n"
          }

Howether. Here's some tips on how to ask questions like these (with not working code samples):

1.  It must run everywhere. Remove the calls to other code (hardcode values if needed), like:

##class(HData.SiteSettings).GetFaxLogin()

2. Remove unused arguments, like coverpath

3. Remove non essential code like:

Set req.SSLConfiguration = "CardChoice"
Do req.InsertFormData("Username",##class(HData.SiteSettings).GetFaxLogin())
Do req.InsertFormData("Password",##class(HData.SiteSettings).GetFaxPassword())
Do req.InsertFormData("ProductId",##class(HData.SiteSettings).GetFaxProductId())
Do req.InsertFormData("cookies","false")
Do req.InsertFormData("header","header")

//Create job name for fax
Set sendDate = +$H
Set sendTime = $P($ZTIMESTAMP,",",2)+(15*60)
Set schedDate = $ZDATETIME(sendDate_","_sendTime,1,4)
Set schedDate = $E(schedDate,1,16)_" "_$E(schedDate,17,18)
Set docList = $LFS(docpath,"\")
Set docName = $LISTGET(docList,$LL(docList))
Do req.InsertFormData("JobName",schedDate_docName)
    
//format phone number and set billing code
Set num = $REPLACE(phone,"-","")
Do req.InsertFormData("BillingCode",num)
Do req.InsertFormData("Numbers1",num)
   
    
//get notification email
Set email = ##class(HData.SiteSettings).GetFaxNotifyEmail()
If (email '= "") Do req.InsertFormData("FeedbackEmail",email)

4. Comment out unused and misleading code paths like

Set base64 = ##class(%SYSTEM.Encryption).Base64Encode(docStream)
Set mimeMsg.ContentTransferEncoding = "base64"

5. Provide a GitHub Gist snippet of an xml file (with the code) to import and write how to run it.

Your goal, is to make it extremely easy for everyone to take a look at your snippet. All the process must consist of these two steps:

  1. Drag&Drop xml file into Studio
  2. Copy&Paste a line into a terminal

I did what you suggested and ended up with

{
   "args": {},
    "data": "",
    "files": {},
    "form": {},
    "headers": {
    "Accept-Encoding": "gzip", "Host": "httpbin.org",
                      "Referer": "http://httpbin.org:80/Polka.Api/REST/SendFax",
                     "User-Agent": "Mozilla/4.0(compatible; Cache;)"
                       },
    "json": null,
     "origin": "216.119.54.2",
      "url": "http://httpbin.org/post"
    }
 

I assume that's a comment  to my answer?

If yes, here's the working code. Maybe I missed some changes in my answer. Because, again, I needed to do too much changes to run the code in the first place.