javascriptgoogle-apps-scriptfile-uploadlarge-filesmultiple-file-upload

Corrupted or Blank file is getting by email through Web app - Google script


Question

Below google script running fine but the file uploaded send via email is corrupted or blank while getting through email.. Attached filename, content type are same as uploaded... but getting file cannot be opened.. text files are fine... Could any one can help in this regard.

Code.gs

function doGet() {
  return HtmlService.createHtmlOutputFromFile('index')
    .setSandboxMode(HtmlService.SandboxMode.IFRAME);
}

function processForm(formObject) {
  var myFile = formObject.myFile;

  var FileBytes = myFile.getBytes();
  var FileType = myFile.getContentType();
  var FileName = myFile.getName();
  var FileToSend = {
    fileName: FileName,
    content: FileBytes,
    mimeType: FileType
  };
  // Logger.log(FileType);

  var FileBytes2 = [100, 97, 121, 32, 108, 97, 32, 110, 111, 105, 32, 100, 117, 110, 103, 32, 98, 101, 110, 32, 116, 114, 111, 110, 103];
  var FileToSend2 = {
    fileName: 'test222.txt',
    content: FileBytes2,
    mimeType: 'text/plain'
  };
  var FileToSend3 = {
    fileName: 'test333.txt',
    content: 'noi dung ben trong',
    mimeType: 'text/plain'
  };

  GmailApp.sendEmail('email@domain', '6 Attachment example', '6 Please see the attached file.', {
    attachments: [FileToSend, FileToSend2, FileToSend3],
    name: '6 Automatic Emailer Script'
  });

  return FileName;
}

index.html


<html>

<head>
  <base target="_top">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
  <script>
    // Prevent forms from submitting.
    function preventFormSubmit() {
      var forms = document.querySelectorAll('form');
      for (var i = 0; i < forms.length; i++) {
        forms[i].addEventListener('submit', function(event) {
          event.preventDefault();
        });
      }
    }
    window.addEventListener('load', preventFormSubmit);

    function handleFormSubmit(formObject) {
      google.script.run.withSuccessHandler(updateUrl).processForm(formObject);
    }

    function updateUrl(filename) {
      var div = document.getElementById('output');
      div.innerHTML = filename;
    }
  </script>
</head>

<body>



  <form action="#" id="myForm" onsubmit="handleFormSubmit(this)" method="post" enctype="multipart/form-data">
    <div class="file-field input-field">
      <div class="btn">
        <span>File</span>
        <input name="myFile" type="file" multiple>
      </div>
      <div class="file-path-wrapper">
        <input class="file-path validate" type="text" placeholder="Upload one or more files">
       </div>
    </div>
          <input type="submit" value="Submit" />
  </form>
<div id="output"></div>


</body>

</html>


Solution

  • To solve your issue, in the handleFormSubmit function, I took an array buffer and transformed it into a string containing the file data and pass it to your processForm function, in order for that logic to be handled in the frontend instead of the backend, google.script.run is a little picky with the values you can pass as arguments. Therefore, your handleFormSubmit function will look like this now:

     const handleFormSubmit = async (formObject) => {
          // Get all the file data
          let file = formObject.myFile.files[0];
          // Get binary content, we have to wait because it returns a promise 
          let fileBuffer = await file.arrayBuffer();
          // Get the file content as binary and then pass it to string 
          const data = (new Uint8Array(fileBuffer)).toString();
          // Pass the file meta data and the content 
          google.script.run.withSuccessHandler(updateUrl).processForm(file.name, file.type, data);
    }
    

    As for the backend function processForm , you will need to transform the data string into a binary data array again, that's why I use JSON.parse("[" + data + "]"). Now, your processForm will look like this:

    function processForm(name, type, data) {
      var fileToSend = {
        fileName: name,
        // Convert the string to a Binary data array
        content: JSON.parse("[" + data + "]"), 
        mimeType: type
      };
      GmailApp.sendEmail('email@domain', '6 Attachment example', '6 Please see the attached file.', {
        attachments: [fileToSend],
        name: '6 Automatic Emailer Script'
      });
      return "this file " + name + " has just been sent to your email";
    }