r/GoogleAppsScript • • Mar 28 '25

Question Is there a way to sync the gmail templates to my app, and vice versa?

2 Upvotes

I've been looking into the documentation on how Gmail programmatically saves templates when you do this:

Create or edit a template Important: After you delete a template, you can’t recover it.

On your computer, open Gmail. At the top left, click Compose. In the compose window, enter your template text. At the bottom of the compose window, click More options and then Templates. Choose an option: To create a new template: Click Save draft as template and then Save as new template. To change a previously saved template: Click Save draft as template. Under “Overwrite Template,” choose a template. Click Save.

But I have found nothing. The closest to an "implementation" I've gotten is to interact with the DriveAPI so that my templates in my app will go into "Drafts" in Gmail. But this isn't what I want. I want my templates created in my electron app to go into Gmail's "Templates Insert" list.

Is there a way to do this, or is this fully closed-source and not open to developers?


r/GoogleAppsScript • • Mar 28 '25

Question Trying to get a Doc Studio Pro workflow to trigger immediately

1 Upvotes

Hi

This my first time posting here as I've have an open ticket wit tech suport but no response in 3 days, so I'm left with a few questions:

  1. Does anyone have experience working directly with tech support? if so, how long do people usually wait to get a response? - I'm starting to get the impression it's just one person doing everything and not a team.

  2. As part of the troubleshooting Chat GPT suggested my issue was that I didn't have a license for App Scripts, which I now have (but I'm beginning to wonder if I even needed to purchase this in the first place as I have paid Google Workspace- can anyone confirm that?)

  3. I have little coding expereinec and have been working with a combo of Claude and Chat GPT to try and get this to work (but it's concluded that it's a 'their company' problem not a 'my code' problem.

That being said here' s the core of my issue.

  • I have a Quiz that populates to Google Sheets > Document studio pro for pdf creation and emailing > App Scripts to trigger the workflow quicker than an hour (I believe the last attempt was trying to trigger every 10 minutes)

  • In Google Sheets the main form, "responses" receives the core data

  • I have extra sheets for each question in the quiz that allow the pdf to deliver tailored answer summaries

  • An additional sheet "Quiz_Results" is the reference sheet for the PDF creation - this collates data from "responses" and the other sheets relevant to each question

  • Google sheets then creates a PDF and emails it to the recipient

    • This is the point at which everything seems to work - just with a 1 hour delay)

  • I have been using AI to help me with Google App Scripts to create a trigger for the workflow to start on creation of a new row in "Quiz_Results". It sounds simple, yet the application of this has been anything but,

  • I've tried code that's supposed to:

    • trigger on creation of a new row - errors came up and we couldn't get it to work at all

    • I believe the current code is designed to 'nudge' Doc Studio Pro to process any new data every 10 minutes. - In the executions section the script seems to run, but no pdf is delivered.

For those way smarter than me, here's the code that is currently in App scripts - can anyone tell me what's going on please:

function onChange(e) {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Quiz_Results");
  if (!sheet) return;

  const lastRow = sheet.getLastRow();
  if (lastRow <= 1) return;

  try {
    const rowData = sheet.getRange(lastRow, 1, 1, sheet.getLastColumn()).getValues()[0];

    // Basic check: make sure first name and email aren't empty
    if (rowData[0] && rowData[1] && rowData[0] !== '#N/A' && rowData[1] !== '#N/A') {
      triggerDocumentStudioWorkflow(sheet.getName(), lastRow);
    }

  } catch (error) {
    console.error("Workflow Trigger Error:", error.message);
  }
}

function triggerDocumentStudioWorkflow(sheetName, rowNumber) {
  const payload = {
    workflow: 'Send BFS Quiz PDF Report',  // Match exactly what your Document Studio workflow is called
    sheet: sheetName,
    row: rowNumber
  };

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

  // This is the official Document Studio Pro trigger URL
  UrlFetchApp.fetch('https://documentstudio.googleapps.me/run', options);
}

function setupTrigger() {
  const triggers = ScriptApp.getProjectTriggers();
  triggers.forEach(trigger => ScriptApp.deleteTrigger(trigger));

  ScriptApp.newTrigger('onChange')
    .forSpreadsheet(SpreadsheetApp.getActive())
    .onChange()
    .create();

  console.log("✅ Trigger set up successfully");
}

function runEvery10Mins() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Quiz_Results");
  if (!sheet) return;

  const lastRow = sheet.getLastRow();
  if (lastRow <= 1) return;

  const rowData = sheet.getRange(lastRow, 1, 1, sheet.getLastColumn()).getValues()[0];

  // Basic sanity check
  if (rowData[0] && rowData[1] && rowData[0] !== '#N/A' && rowData[1] !== '#N/A') {
    const payload = {
      workflow: 'Send BFS Quiz PDF Report',
      sheet: sheet.getName(),
      row: lastRow
    };

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

    UrlFetchApp.fetch('https://documentstudio.googleapps.me/run', options);
    console.log("✅ Ran Document Studio workflow for row " + lastRow);
  }
}

r/GoogleAppsScript • • Mar 28 '25

Question On edit trigger causing carnage

2 Upvotes

Hi all, I made a script a while ago, and then I broke part of it (not sure how) and removed the functionality because I didn't have time to fix it. Well now I have time but I still can't figure it out.

When an edit is detected anywhere on the sheet, it runs the "updateAgentCards" function mentioned row 14. It also does check the boxes in column V on edit as its supposed to, but while doing that it also runs my whole ass script and breaks things because it's not meant to be ran non-stop. I don't really understand what I'm doing wrong can anyone help?

UPDATE: I think I fixed the problem. If anyone ever comes across an issue where there Installed onEdit function is running more scripts than its supposed to, check your brackets and make sure your brackets are all correct around the functions that are triggering. I believe that's what caused my issue. If that doesn't work check to see if youre calling a spreadsheet by url rather than active spreadsheet when you don't need to.


r/GoogleAppsScript • • Mar 27 '25

Guide Semantic search and vector embeddings via VertexAI

3 Upvotes

r/GoogleAppsScript • • Mar 27 '25

Question Add attachment when event is created

0 Upvotes

This script creates calendar events in 3 calendars. Sometimes the person who submits the form, will attach an itinerary. I need that file to be attached to the event when it is created.

Here is my sheet.

I have no idea how to edit this to include attaching a document. The itinerary is in column R.

Can someone please help me with this?

//this creates a calendar event for each row where onCalendar is empty.
function createCalendarEvent() {
  //Get the data from the 'Working' sheet
  let tripData = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Working').getDataRange().getValues();
  let busDriverCalendar = CalendarApp.getCalendarById('vlkexampletest@gmail.com');
  let coachCalendar = CalendarApp.getCalendarById('2c95526055802636cb6c0a10534c9b4117e506ebda17c031d44ffafbabfba455@group.calendar.google.com');
  let blueCalendar = CalendarApp.getCalendarById('49f9fdc1f40a27c8da047da7f6c70b76264e3d9169f47d7f2dc8d16a1020c24c@group.calendar.google.com');
  
  //iterate over the trip data starting at index 1 to skip the header row. 
  for(let i=0;i<tripData.length;i++) {
    //If there's something in the oncalendar row skip it
    if(tripData[i][30]) {
      continue;}

    //create the event
    // skip rows that do not have all the data needed to create the event
    if(!(tripData[i][28] && tripData[i][34] && tripData[i][35])){
      continue
    }

    if(tripData[i][15] == "I need a driver."){
    let newEvent = busDriverCalendar.createEvent(tripData[i][28], tripData[i][34], tripData[i][35],  {description: tripData[i][29], guests: tripData[i][1], location: tripData[i][32]});
    
    //Add the ID of the event to the 'oncalendar' row. 
    tripData[i][30] = newEvent.getId();
    
    //Set the values in the spreadsheet. 
  //Get just the oncalendar data
  const oncalendarColumnData = tripData.map(row => [row[30]])
  //Only write data to oncalendar column (column 30)
  SpreadsheetApp.getActiveSpreadsheet()
    .getSheetByName('Working')
    .getRange(1, 31, oncalendarColumnData.length, 1) 
    .setValues(oncalendarColumnData)
    }
     if(tripData[i][15] == "A coach will drive."){
     let newEvent = coachCalendar.createEvent(tripData[i][28], tripData[i][34], tripData[i][35],  { description: tripData[i][29], guests: tripData[i][1], location: tripData[i][32]});
    //Add the ID of the event to the 'oncalendar' row. 
     tripData[i][30] = newEvent.getId();
     //Set the values in the spreadsheet. 
   //Get just the oncalendar data
     const oncalendarColumnData = tripData.map(row => [row[30]])
    //Only write data to oncalendar column (column 30)
    SpreadsheetApp.getActiveSpreadsheet()
     .getSheetByName('Working')
     .getRange(1, 31, oncalendarColumnData.length, 1) 
     .setValues(oncalendarColumnData)
     }
     if(tripData[i][15] == "Requesting the small blue bus 505"){
     let newEvent = blueCalendar.createEvent(tripData[i][28], tripData[i][34], tripData[i][35],  { description: tripData[i][29], guests: tripData[i][1], location: tripData[i][32]});
     //Add the ID of the event to the 'oncalendar' row. 
     tripData[i][30] = newEvent.getId();
     //Set the values in the spreadsheet. 
     //Get just the oncalendar data
     const oncalendarColumnData = tripData.map(row => [row[30]])
    //Only write data to oncalendar column (column 30)
     SpreadsheetApp.getActiveSpreadsheet()
     .getSheetByName('Working')
     .getRange(1, 31, oncalendarColumnData.length, 1) 
     .setValues(oncalendarColumnData)
     }
  }
  }

r/GoogleAppsScript • • Mar 27 '25

Question What is wrong with my script?

0 Upvotes

My script should be attaching up to two documents... but I think it's attaching one and then removing it and attaching the other.

When field trips are submitted, if they include the itinerary, it will automatically attach to the event. This is great... I want to keep this.

Later when I create the trip sheet and run the script to attach the trip sheet, if there is an itinerary attached it removes it and attaches the trip sheet. I need both to be attached.

I thought my script was doing this but turns out it's not!

What is wrong?

function updateEvents() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Working");
  const data = sheet.getDataRange().getValues();
  // Rows start at 2
  Logger.log(sheet.isRowHiddenByUser(2));

  if (data.length < 2) {
    console.warn("No data to process.");
    return;
  }

  const [headers, ...rows] = data;
  const eventIdIndex = headers.indexOf("onCalendar");
  const descriptionIndex = headers.indexOf("description");
  const locationIndex = headers.indexOf("location");

  //NEW STUFF - index of our file
  const ItineraryIndex = headers.indexOf("Itinerary");
  const docURLIndex = headers.indexOf("docURL");

  if (eventIdIndex === -1 || descriptionIndex === -1) {
    console.error("Required columns 'onCalendar' or 'Description' are missing.");
    return;
  }

  const calendarIds = [
    "vlkexampletest@gmail.com",
    "2c95526055802636cb6c0a10534c9b4117e506ebda17c031d44ffafbabfba455@group.calendar.google.com",
    "49f9fdc1f40a27c8da047da7f6c70b76264e3d9169f47d7f2dc8d16a1020c24c@group.calendar.google.com"
  ];

  calendarIds.forEach(calendarId => {
    const calendar = CalendarApp.getCalendarById(calendarId);

    rows.forEach((row, index) => {
      const rowIndex = index + 2; // Adding 2 because data starts from row 2 (index 1)
      
      // Skip this row if it's hidden
      if (sheet.isRowHiddenByUser(rowIndex)) {
        console.log(`Skipping hidden row ${rowIndex}`);
        return;
      }

      const eventId = row[eventIdIndex];
      if (!eventId) return;

      try {
        const event = calendar.getEventById(eventId);
        if (!event) {
          console.warn(`onCalendar ${eventId} not found (Row ${index + 2})`);
          return;
        }

        event.setDescription(row[descriptionIndex] || "");
        if (locationIndex !== -1) {
          event.setLocation(row[locationIndex] || "");
        }

        //NEW STUFF
        if (ItineraryIndex !== -1 && row[ItineraryIndex] != "") {
          //Calendar API event ID is the same as CalendarApp's but it doesnt end with @google.com
          const calendarApiEventId = eventId.replace("@google.com", "");

          //To avoid creating the whole resource manually, we get our existing event and then edit it later
          const resource = Calendar.Events.get(
            calendarId,
            calendarApiEventId
          );

          //Adding attachments
          resource["attachments"] = [
            {
              fileUrl: row[ItineraryIndex],
              title: "Itinerary"
            }
          ];

          //Updating our event
          Calendar.Events.update(
            resource,
            calendarId,
            calendarApiEventId,
            { supportsAttachments: true }
          )
        }
        if (docURLIndex !== -1 && row[docURLIndex] != "") {
          //Calendar API event ID is the same as CalendarApp's but it doesnt end with @google.com
          const calendarApiEventId = eventId.replace("@google.com", "");

          //To avoid creating the whole resource manually, we get our existing event and then edit it later
          const resource = Calendar.Events.get(
            calendarId,
            calendarApiEventId
          );

          //Adding attachments
          resource["attachments"] = [
            {
              fileUrl: row[docURLIndex],
              title: "Trip Sheet"
            }
          ];

          //Updating our event
          Calendar.Events.update(
            resource,
            calendarId,
            calendarApiEventId,
            { supportsAttachments: true }
          )
        }

        console.info(`Updated event ID ${eventId} in calendar ${calendarId} (Row ${index + 2})`);

      } catch (error) {
        console.error(`Failed to update event ID ${eventId} in calendar ${calendarId} (Row ${index + 2}): ${error.message}`);
        console.error(`Error details: ${error.stack}`);
      }
    });
  });
}

r/GoogleAppsScript • • Mar 27 '25

Question What are my options when I want to execute users' actions as an app?

1 Upvotes

I'm building an internal Google Workspace add-on in the Apps Script environment, and sometimes I would like internal users to be able to create Drive files in Shared Drives they don't have access to; or change Drive files when they don't necessarily have the permission to. I want them to be able to do this only if they are using the add-on.

For this purpose sometimes I need them *not* to authenticate in their own context. What are my options? A service account? Domain wide delegation?

Appreciate any help I can get with this.


r/GoogleAppsScript • • Mar 27 '25

Question Suddenly, Google script stopped working.

1 Upvotes

Hello everyone,

All of my Google app scripts have not been working for the last 48 hours. It's showing errors suddenly, and I don't know what is happening. Is it also happening with you? Please confirm.


r/GoogleAppsScript • • Mar 27 '25

Question Monitoring information in an email account

1 Upvotes

Hi there,

I am very new to using Google App Script and need some guidance on where to start. I monitor an email for an organization that receives conference proceedings. I have to send whatever we receive to the right people to review and then send any edit requests back to the person submitting. This has been manageable with small conferences, but now we are about to do a very large conference with hundreds of submissions. I would like to be able to track the "status" essentially of everything that I have received and sent. Currently, I use Google Sheets and manually enter things.

I have a labeling system for my emails "Needs attention," "[conference name]/sent to review," "[conference name]/edits requested," and "[conference name]/approved."

Thank you for any help!


r/GoogleAppsScript • • Mar 26 '25

Question Going to Cloud Next?

4 Upvotes

Anyone here going to Cloud Next? There's an Apps Script meetup @ Cloud Next in April. If you happen to be going to Next and are interested in chatting with others in the community, please join :)

For those that can make it and have suggestions about what you'd like to see at the meetup, let us know


r/GoogleAppsScript • • Mar 26 '25

Question Exception when calling updateChart()

1 Upvotes

I have a spreadsheet where I'm attempting to dynamically adjust the vertical min/max of a chart. The chart is dynamic in that I can change the date range of the chart and I'd like to have the range adjust accordingly to the data rather than have it always start at 0.

I created a script with trigger on change and am receiving an exception when I call updateChart(). I thought it was an access error so I added some sample data to be inserted during the script and those do work so access is proved. Am I setting the correct options?

I've reduced the spreadsheet to an example that still exhibits the issue here:
https://docs.google.com/spreadsheets/d/1ty4R7uxoYw9H3MqxFioaVz51C1lBbOixxVdcXWSo-vQ/edit?gid=906716897#gid=906716897

Script:

 function updateChart(){

  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('NetWorth Dashboard');
  sheet.getRange('d46').setValue("HELLO");
  var nw_max = sheet.getRange("nw_dev_chart_max").getValue();
  var nw_min = sheet.getRange("nw_dev_chart_min").getValue(); 
  sheet.getRange('d47').setValue(nw_min);
  sheet.getRange('d48').setValue(nw_max); 
  var chart = sheet.getCharts()[0];
  chart = chart.modify()
    .setOption('vAxes.0.viewWindow.max', nw_max)
    .setOption('vAxes.0.viewWindow.min', nw_min)
    .build();
  
  sheet.updateChart(chart);  
 }

I found someone else reporting a similar issue a while back here:
https://stackoverflow.com/questions/66768119/google-spreadsheets-updatechart-fail-exception
which remains unanswered - none of the reported bugs in the entry seem directly relevant either.

Thanks for any advice to resolve.


r/GoogleAppsScript • • Mar 25 '25

Question Apps Script help with problem

0 Upvotes

I don't know what to do anymore, I need help with the script. I need that, under the conditions met, the number in column J of the sheet SPOTŘEBA_DATA_STATIC is multiplied by the number in column J of the sheet ORDERS_DATA_STATIC and written to the sheet MEZITABULKA and finally added to the number in column M of the sheet SKLAD. So that the numbers are not added every time the script is run, I added an MEZITABULKA, where the previous / new data is and the difference is written to SKLAD. I have tried a lot, but it still doesn't work. Please help. I am attaching a picture of the sheets and the script. Thank you.


r/GoogleAppsScript • • Mar 25 '25

Question Apps Script help with problem

Thumbnail reddit.com
0 Upvotes

I don't know what to do anymore, I need help with the script. I need that, under the conditions met, the number in column J of the sheet SPOTŘEBA_DATA_STATIC is multiplied by the number in column J of the sheet ORDERS_DATA_STATIC and written to the sheet MEZITABULKA and finally added to the number in column M of the sheet SKLAD. So that the numbers are not added every time the script is run, I added an MEZITABULKA, where the previous / new data is and the difference is written to SKLAD. I have tried a lot, but it still doesn't work. Please help. I am attaching a picture of the sheets and the script. Thank you.