2

I'm creating a sidebar form within Google Sheets using Google Apps Script where users can upload at least one image. After that, I want to get the Base64 encoded content of each image and the image's file name. Then, I will make a request to SendGrid's API to create and send an email with attachments being the images that the user has uploaded.

Here is the code I have so far:

Form.html

<form onsubmit="handleFormSubmit(this)">
    <div class="custom-file">
        <input type="file" class="custom-file-input" id="images_input" name="images_input" multiple required>
        <label class="custom-file-label" for="images_input">Select images...</label>
    </div> 
    <button type="submit">Submit</button>
</form>

<script>
function handleFormSubmit(formObject) {
    google.script.run.processForm(formObject);
}
</script>

Code.gs

function processForm(formObject) {
    var images = formObject.images_input;
    var base64Images = Utilities.base64Encode(images);

    // Set up the request to SendGrid
    var API_KEY = PropertiesService.getScriptProperties().getProperty('API_KEY');
    var sendGridUrl = 'https://api.sendgrid.com/v3/mail/send';

    var headers = {
        'Authorization': 'Bearer ' + API_KEY
    };

    var data = {
        "personalizations": [{
            "to": [{
                "email": ...
            }],
            "dynamic_template_data": {
                ...
            }
        }],
        "attachments": [{
            "content": base64Images,
            "filename": "somefilename"
        }],
        "from": {
            "email": ...
        },
        "template_id": ...",
    };

    var options = {
        'method': 'post',
        'contentType': 'application/json',
        'headers': headers,
        'payload': JSON.stringify(data)
    };

    UrlFetchApp.fetch(sendGridUrl, options);
}

It's not working (obviously). I'm stuck at the part where I need to get the Base64 encoded content of each image: I don't think I'm doing that correctly. Should I use FileReader on the client-side, or Utilities.base64Encode on the server-side do get what I want? Any ideas are appreciated!

1 Answer 1

1

I believe your goal as follows.

  • You want to retrieve the file and send it to Google Apps Script as base64 data.

I think that in this case, you can retrieve the file using FileReader as you have already mentioned. When FileReader is used, the base64 data can be directly retrieved at Javascript side. So when your script is modified, it becomes as follows.

Modified script:

HTML&Javascript side:

From:
function handleFormSubmit(formObject) {
    google.script.run.processForm(formObject);
}
To:
function handleFormSubmit(formObject) {
  Promise.all([...formObject.images_input.files].map((file, i) => {
    const fr = new FileReader();
    return new Promise((r) => {
      fr.onload = (f) => r({filename: file.name, base64Data: f.target.result.split(",")[1]});
      fr.readAsDataURL(file);
    });
  }))
  .then((obj) => {
    google.script.run.processForm(obj);
  });
}

Google Apps Script side:

From:
function processForm(formObject) {
    var images = formObject.images_input;
    var base64Images = Utilities.base64Encode(images);
To:
function processForm(base64Images) {
  • In this case, base64Images is an array like [{base64Data: "###base64ImageData1###", filename: "filename1"},{base64Data: "###base64ImageData2###", filename: "filename2"},,,].

Note:

  • In this modification, it supposes that you have alredy been able to use the API you want to use. Please be careful this.

Reference:

Sign up to request clarification or add additional context in comments.

3 Comments

Wouldn't this encode work only for the first image and not for the entire array of images? Because this line fr.readAsDataURL(formObject.images_input.files[0]); just reads the first image.
@Sami Junior Thank you for replying. I overlooked multiple required. I apologize for this. So I updated my answer. Could you please confirm it?
@Sami Junior Thank you for replying. I'm glad your issue was resolved. Thank you, too.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.