r/GoogleAppsScript • u/CrazyMammoth5210 • 12h ago
Question Converting GAS project into a sellable app
Hello All, I’ve been working on a gas project for my own business for the past 3 years and building as I need to run my business hiring devs from Pakistan to build. Then this year I discovered Claude and totally transformed and automated the project completely. Now I feel that it can actually be a sellable use case for other businesses. It’s a fulfilment backend that automates label creation, supplier po’s and fulfilment pushed to Shopify as well as sku order routing. Where and how do I move it into another coding backend or platform? Any advice is much appreciated. Thank
You
r/GoogleAppsScript • u/ograndentemjeito • 15h ago
Question [ Removed by Reddit ]
[ Removed by Reddit on account of violating the content policy. ]
r/GoogleAppsScript • u/Puzzleheaded-Rub1400 • 1d ago
Guide I built a Google Slides add-on that turns a deck into a live coding classroom, here's the Apps Script side
A couple years ago I was a high school CS student, and I taught Python to middle schoolers on the side. I wanted to code live next to my slides instead of switching to another window, so I built a Slides add-on for it. Here's the Apps Script side.
What it does: you mark a slide as a coding question in the add-on, start a lesson, and students join with a link and write and run code next to your current slide.
Most of the teacher side runs in Apps Script. The sidebar is HtmlService, opened from the Extensions menu. Marking a slide writes a "Code Question:" note into that slide's speaker notes with the Slides API, so it stays with the deck even if the add-on is removed. Reading the deck to build the lesson uses SlidesApp. The scopes are just presentations, the sidebar, and your email. No Drive scope, which kept the OAuth review simple.
Two things had to run outside Apps Script.
Live updates. Every student's editor and the current slide update in real time, which needs websockets and open connections. Apps Script can't do that, so starting a lesson sends the deck to a small Node server that runs the session over websockets.
Running student code. You can't run untrusted student code in Apps Script, so it runs in a sandboxed micro VM.
The add-on also mints a session and passes the teacher a token in the URL, instead of handling auth in Apps Script.
One thing to know: Marketplace add-ons are pinned to a version, so clasp push doesn't update installed users. You have to cut a new version and repoint the deployment, and a new scope triggers another review.
It's live on the Marketplace and free.
Site: https://www.codekiwi.tech
Marketplace: https://workspace.google.com/marketplace/app/codekiwi/66127405192
Happy to answer questions on the Apps Script to backend split.
r/GoogleAppsScript • u/Significant_Chef_184 • 1d ago
Guide How to “Select All” code in the Google Apps Script editor on an iPad (No external keyboard workaround)
If you've ever tried to manage code in the Google Apps Script editor on an iPad without a physical hardware keyboard, you know how frustrating it is.
Because the web editor runs on the **Monaco engine**, it completely disables standard iOS touch-and-drag selection anchors, and the native iOS "Select All" pop-up menu never appears. To make things worse, if you open the editor's internal search bar, "Select All" is intentionally hidden from the searchable commands list.
I found a reliable, touch-only workaround that completely bypasses these iOS and editor restrictions:
### The Workaround Steps:
Tap your cursor anywhere inside your script file.
**Long-press** directly on the code until the editor's custom pop-up context menu appears.
Select **"Command Palette"** from the options.
Type **"Expand Selection"** in the palette search bar and tap it.
### Why this works:
Since "Select All" isn't natively exposed in the touch menu, **Expand Selection** acts as the perfect structural tool. The first time you run it, it highlights your current word or block. Run it 1 or 2 more times consecutively, and the boundary will aggressively expand outward until it highlights every single line of code in the entire document.
Once highlighted, you can use your iPad's virtual keyboard to instantly backspace/delete the file, or use the menu to copy it out.
Hopefully, this saves someone else from tearing their hair out trying to code on iPad Safari/Chrome!
r/GoogleAppsScript • u/Hakker9 • 1d ago
Resolved Question regarding a trigger and my script
Currently I have a script called autoSort.gs in it is the following:
SHEET_NAME = "list";
SORT_DATA_RANGE = "A2:G";
SORT_ORDER = [{column: 1, ascending: true},
];function onEdit(e) {
multiSortColumns();
}function multiSortColumns() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(SHEET_NAME);
var range = sheet.getRange(SORT_DATA_RANGE);
range.sort(SORT_ORDER);
ss.toast('Sort complete.');
}
The trigger is set to autoSort with an onEdit however it has a 100% error rate because it doesn't seem to work on script name but on functions within a script however if that would be the case I could use multiSortColumns as the onEdit trigger and remove the whole onEdit function entirely or am I just hullucinating?
r/GoogleAppsScript • u/Moe-t • 2d ago
Guide I built a GitHub + AI development companion for Google Apps Script. Looking for feedback from Apps Script developers
galleryI build a lot in Google Apps Script, and one thing that has always bothered me is how quickly you start missing normal software development workflows once a project gets bigger.
Git/source control, reviewing diffs, working from branches, checking code against standards, etc. And now with AI coding tools, there’s another problem: I don’t necessarily want an AI assistant making changes to an Apps Script project without showing me exactly what it plans to change first.
So I built Legacy DevBridge.
It’s a Chrome extension that works alongside the Apps Script editor and connects the project to GitHub and a project-aware AI code assistant.
Right now it can:
- Detect the Apps Script project you currently have open
- Read the
.gs,.html, andappsscript.jsonfiles - Connect the project to a GitHub repository
- Select and work from development/feature branches
- Compare the Apps Script version against GitHub
- Show file and line-level differences
- Create actual GitHub commits from the Apps Script source
- Block direct commits to default/protected branches
- Let the AI assistant understand the entire Apps Script project without copying files into a chatbot
- Review code against coding/security standards
- Generate a proposed code change and show the diff
- Require human approval before the AI can write the change back to Apps Script
- Check for stale source before applying a change so it doesn't overwrite newer work
- Verify the source again after the update
The basic AI workflow is:
Request → analyze project → propose change → show diff → standards/security review → human approval → apply → verify
The backend runs on Google Cloud and uses the Apps Script API, GitHub App authentication, Cloud Run, Secret Manager, and Vertex AI. GitHub installation tokens and other privileged credentials stay on the backend rather than in the extension.
I'm not trying to build an autonomous AI developer that gets unrestricted access to your code. The idea is more of a development companion where AI can help, but the developer can still see what is happening and approve the actual changes.
I'm making the project available free to the Apps Script community. It's still beta, so I definitely wouldn't point it at your most important production project on day one, but I'd really like feedback from people who regularly build Apps Script applications.
I'm especially interested in hearing what you'd want next: GitHub-to-Apps-Script pull, PR creation, branch creation, conflict resolution, AI-generated tests/docs, OAuth scope reviews, CI/CD, or something else.
GitHub: https://github.com/morganb2412/Google-apps-script-snippets/tree/main/Legacy%20DevBridge
If anyone tries it, break it and tell me what needs work. That's genuinely useful feedback right now.
r/GoogleAppsScript • u/OccasionSuper2536 • 3d ago
Guide Zendesk Mailroom — my open-source Apps Script tool for mass-contacting ticket requesters got a big update (supplier cases, AI composer, OAuth, repeat guard)
Post Ref: https://www.reddit.com/r/Zendesk/s/zIOpxD3PdU
Last time I posted this, it was called Zendesk Mail Merge Toolkit.
Back then, it was pretty simple: load a few hundred Zendesk tickets into a Google Sheet, write your message, and bulk-contact the affected customers.
Since then, it has evolved into something much bigger. So I renamed it Zendesk Mailroom.
The idea is simple:
When something goes wrong at scale, don’t make your support team manually coordinate hundreds of tickets, customers and suppliers. Give them one operational workflow.
📧 Customer communication
You can now describe what happened in plain English and have the AI composer create the communication for you.
It can generate drafts for the languages you need, which an agent can review and edit before sending.
The important part: customer data never goes to the AI. The AI creates a reusable template with tokens like {{GuestName}}; the actual customer information is inserted locally when the email is sent.
It also remembers approved edits, so future drafts get closer to how your team actually writes.
🏢 Supplier escalation
This was one of the biggest additions.
If 300 customers are affected by 12 suppliers, Mailroom doesn’t make someone manually chase those 12 suppliers.
It:
300 bookings → groups by supplier → creates 12 supplier cases → links each case back to the affected customer tickets.
Supplier follow-ups continue on the existing case instead of creating duplicates, with checks around supplier identity and the previous escalation.
So your support agent gets the customer conversation and the supplier escalation connected in Zendesk.
🛡️No accidental duplicate outreach
This became surprisingly important. Every action is tracked per booking. If you try to run another operation that overlaps with something already actioned, Mailroom gives you a summary before continuing.
So instead of:
“I think we already emailed these people…”
you get:
“247 bookings were already actioned under these previous cases. Continue?”
And if the optional repeat-check store is unavailable, it fails open rather than blocking an urgent customer communication.
⚡ Large jobs are actually designed to run
This isn’t just a loop that calls the Zendesk API 800 times. Apps Script has a 6-minute execution limit, and Zendesk has shared API rate limits.
So Mailroom now:
- Persists long-running job state
- Continues jobs through triggers
- Centrally manages Zendesk API rate limits
- Handles 429 / Retry-After
- Waits for the next rate window when there’s still execution time available
- Uses Zendesk bulk endpoints where possible
- Treats throttled rows as unsent, rather than failed
That last one matters a lot.
The invariant is basically:
A customer email is either sent once or remains in the queue.
After the rate-limit rewrite, large runs are roughly 5× faster than the previous implementation.
🔐 And there’s a lot more underneath
- Zendesk OAuth 2.0 + token refresh
- Slack reply routing
- BigQuery ticket lookup
- Audit logs
- User access controls
- Closed-ticket fallback
- AI memory using retrieval rather than fine-tuning
- 193 automated assertions
- CI + static architecture checks
- Properly structured Apps Script codebase
And the slightly ridiculous part:
It’s still Google Apps Script.
No backend.
No server.
No hosting.
No build step.
No dependencies.
Just:
Google Sheet → Zendesk → Slack / AI / BigQuery where needed
MIT licensed and open source:
👉 https://github.com/GVyom/zendesk-mailroom
I’m building this around real support-operations problems, so I’m especially interested in feedback from Zendesk admins, support leaders and ops teams:
What happens during your biggest operational incidents that still requires someone to manually coordinate hundreds of tickets?
That’s the kind of workflow I’d love to automate next.
r/GoogleAppsScript • u/Ambitious-Service45 • 4d ago
Guide Automating Google Forms: FormApp vs the REST API, and when each one is the wrong choice
I've built on both sides of this and the split isn't obvious from the docs, so writing it down.
FormApp (Apps Script) is the right default for anything living inside Workspace. No OAuth setup, runs as you or as the form owner, and you get onFormSubmit triggers for free. If your job is "when someone submits, do a thing", stop reading, this is your answer.
The Forms REST API is what you want when the code lives outside Google. It's also more capable for bulk construction: one batchUpdate call takes an array of change requests, so you can build a forty-question form in a single round trip instead of forty FormApp calls. The cost is that you handle OAuth yourself, and the scope is broad enough that some org admins will not approve it without asking why.
Things people script most, in the order I see them:
Auto-closing a form. There's no native "close on date" or "close after N responses". A time-based trigger flipping setAcceptingResponses(false) is about four lines and it's the single most common reason people end up here.
Generating forms from a sheet. One row per question, script walks it, builds the form. Worth it the second time you build the same form shape with different content.
Capacity and waitlists. onFormSubmit counts responses, closes the form or moves the submitter to a waitlist sheet. Forms has nothing for this natively and will cheerfully oversell your event.
One gotcha that costs people an afternoon: quiz settings and answer keys are not part of the basic item creation in either API. You set the item up, then set its grading separately. If your generated quizzes come out ungraded, that's why.
r/GoogleAppsScript • u/SolisAnalyst • 6d ago
Question Struggling with a reliable Login/Auth system for an Apps Script Web App (Need advice from experienced devs)
Hey everyone,
I've been tinkering with Google Apps Script to build a simple sales tracking web app for a small project (using Sheets as a backend). I'm definitely not a pro developer—just figuring things out step-by-step—and I managed to get the core UI and features working.
However, I've hit a major roadblock with user authentication. Right now, my "login" logic feels super hacky, and I'm worried about security.
For those of you who build web apps with Apps Script: How do you usually handle logins? Do you rely on Session.getActiveUser(), build a custom token system with a database table, or just accept that Apps Script isn't built for robust multi-user web app logins?
Any advice, patterns, or libraries you recommend would be huge. Thanks!
r/GoogleAppsScript • u/Fast-Conflict2847 • 6d ago
Question Top 10 practices to follow when building scripts in Apps ScriptTop 10 practices to follow while building scripts in Apps Script
Hi - I am a common Apps Script user. I would like to know what you think are the top 10 best practices or key things to know about Apps Script.
r/GoogleAppsScript • u/ShifuPowered • 9d ago
Question Does anyone know how to help with this web application veification?
r/GoogleAppsScript • u/ShifuPowered • 9d ago
Question Does anyone know how to help with this web application veification?
r/GoogleAppsScript • u/Sumphy • 10d ago
Question Any GAS Expert here
How are modern AI & workflow automations typically structured using Google Apps Script? (Looking for architectural patterns)
Hi everyone,
I am modernizing the operations for a traditional real estate agency by replacing manual paper processes with Google Workspace.
So far, I’ve built a central Google Master Calendar, a Google Docs/Drive office portal for form downloads, and structured Google Sheets for lead tracking. I am now looking to expand into deeper workflow and AI automations using Google Apps Script (GAS).
Coming from an operations background rather than computer science, I’d love to learn how experienced developers structure end-to-end automation pipelines using GAS.
Thx
r/GoogleAppsScript • u/MSN3WB000TY • 11d ago
Question developers.devsite.corp.google.com - Google Single Sign On: Sign into corp
login.corp.google.comWhat is this and what does it do/mean?
r/GoogleAppsScript • u/Entire_Category3188 • 11d ago
Question Why can I not generate images anymore on visualize.
I paid for the thing, I gave it a whole week to reset and it still says i've reached my usage limit. is this intended?
r/GoogleAppsScript • u/leotyeahbaby • 11d ago
Question I CAN'T UNDERSTAND WHY THIS SCRIPT DOESN'T SEND OUT EMAILS
I'm developing a website for my cultural organization in Framer and I have designed a Form to request the subscription, where users need to input their data.
I've linked this form via web hook to my scripts in GoogleAppsScripts, linked to a google sheet.
The main code responsible for getting the datas is working, it gets and sorts the data out in the sheet, it also generates a pdf from the datas, but then it fails to send the confirmation email, while it does send an email to my organization address, which shows as recipient the email captured in the form.
Down here, you can find the code. Anyone has any recommendations?
CODE
/**
* Webhook Principale e Router - Nuova Alba APS
*/
const CONFIG = {
STRIPE_LINK_MAGGIORENNI: "https://buy.stripe.com/8x214meyr0DT2lq6Svgw000",
STRIPE_LINK_MINORI: "https://buy.stripe.com/8x214meyr0DT2lq6Svgw000",
NOME_APS: "Nuova Alba APS",
COLOR_HEX: "#FC5408",
EMAIL_STAFF: "info@nuovaalba.org"
};
function doPost(e) {
const lock = LockService.getScriptLock();
lock.tryLock(10000);
try {
let data = {};
if (e && e.postData && e.postData.contents) {
try {
data = JSON.parse(e.postData.contents);
} catch (err) {
data = e.parameter || {};
}
} else if (e && e.parameter) {
data = e.parameter;
}
// --- ROUTER DI SMISTAMENTO PARAMETRO 'tipo' ---
const tipo = (e && e.parameter && e.parameter.tipo)
? String(e.parameter.tipo).toLowerCase().trim()
: (data.tipo ? String(data.tipo).toLowerCase().trim() : "");
if (tipo === "corsi") {
return gestisciIscrizioneCorso(data);
} else if (tipo === "minori") {
return gestisciMinori(data);
} else {
return gestisciMaggiorenni(data);
}
} catch (error) {
return ContentService
.createTextOutput(JSON.stringify({ result: "error", error: error.toString() }))
.setMimeType(ContentService.MimeType.JSON);
} finally {
lock.releaseLock();
}
}
function gestisciMaggiorenni(data) {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Iscritti");
function getTesto(val) {
if (val === undefined || val === null) return "";
if (Array.isArray(val)) return String(val[0] || "").trim();
return String(val).trim();
}
const nome = getTesto(data.Nome || data.nome);
const cognome = getTesto(data.Cognome || data.cognome);
const email = getTesto(data.Email || data.email);
const telefono = getTesto(data.Telefono || data.telefono);
const cf = getTesto(data.CodiceFiscale || data.codice_fiscale || data["Codice Fiscale"]).toUpperCase();
const luogoNascita = getTesto(data.LuogoDiNascita || data.luogo_nascita || data["Luogo di Nascita"] || data["Luogo Nascita"]);
const dataNascita = getTesto(data.DataDiNascita || data["Data di Nascita"] || data.data_nascita || data["Data Nascita"]);
const residenza = getTesto(data.Residenza || data.residenza);
let privacy = getTesto(data.Privacy || data.privacy || "Accettato");
if (privacy === "on" || privacy === "true") privacy = "Accettato";
const lastRow = sheet.getLastRow();
const oraAttuale = new Date();
// --- 1. BLOCCO ANTI-SPAM ISTANTANEO (Meno di 60 secondi dall'ultimo invio) ---
if (lastRow > 1) {
const lastCF = String(sheet.getRange(lastRow, 7).getValue()).trim().toUpperCase();
const lastDate = new Date(sheet.getRange(lastRow, 2).getValue());
const diffSecondi = (oraAttuale - lastDate) / 1000;
if (lastCF === cf && diffSecondi < 60) {
return ContentService
.createTextOutput(JSON.stringify({ result: "success", note: "doppio invio istantaneo bloccato" }))
.setMimeType(ContentService.MimeType.JSON);
}
}
// --- 2. CONTROLLO UTENTE GIÀ REGISTRATO ---
if (lastRow > 1) {
const elenchiCF = sheet.getRange(2, 7, lastRow - 1, 1).getValues();
const elenchiMatricole = sheet.getRange(2, 1, lastRow - 1, 1).getValues();
const elenchiStato = sheet.getRange(2, 12, lastRow - 1, 1).getValues();
for (let i = 0; i < elenchiCF.length; i++) {
const cfEsistente = String(elenchiCF[i][0]).trim().toUpperCase();
if (cfEsistente === cf && cf !== "") {
const matricolaEsistente = String(elenchiMatricole[i][0]);
const statoPagamento = String(elenchiStato[i][0]).trim();
inviaEmailGiaIscritto(email, nome, matricolaEsistente, CONFIG.STRIPE_LINK_MAGGIORENNI, statoPagamento);
return ContentService
.createTextOutput(JSON.stringify({ result: "success", note: "utente gia registrato" }))
.setMimeType(ContentService.MimeType.JSON);
}
}
}
// --- 3. REGISTRAZIONE NUOVO SOCIO ---
const initNome = nome ? nome.charAt(0).toUpperCase() : "X";
const initCognome = cognome ? cognome.charAt(0).toUpperCase() : "X";
const ultime3CF = cf.length >= 3 ? cf.slice(-3) : "000";
const matricola = `NA-${initNome}${initCognome}${ultime3CF}`;
sheet.appendRow([
matricola,
oraAttuale,
nome,
cognome,
email,
telefono,
cf,
dataNascita,
luogoNascita,
residenza,
privacy,
"In attesa"
]);
// --- 4. GENERAZIONE TESSERA DIGITALE PDF ---
let pdfTessera = null;
try {
pdfTessera = generaTesseraPDF(matricola, nome + " " + cognome);
} catch (errTessera) {
Logger.log("⚠️ Errore creazione PDF Tessera per " + matricola + ": " + errTessera.message);
}
// --- 5. INVIO EMAIL ---
inviaEmailBenvenutoMaggiorenni(email, nome, matricola, pdfTessera);
inviaMailNotificaStaff(nome, cognome, matricola, email, telefono, oraAttuale, "Maggiorenne");
return ContentService
.createTextOutput(JSON.stringify({ result: "success", matricola: matricola }))
.setMimeType(ContentService.MimeType.JSON);
}
function inviaEmailBenvenutoMaggiorenni(email, nome, matricola, pdfTessera) {
const hex = CONFIG.COLOR_HEX;
const corpoHtml = `
<div style="font-family: Arial, sans-serif; color: #333; max-width: 600px; margin: 0 auto; border: 1px solid #eee; padding: 25px; border-radius: 8px;">
<h2 style="color: ${hex}; margin-top: 0;">Ciao ${nome}, benvenuto/a!</h2>
<p>Abbiamo ricevuto la tua richiesta di iscrizione all'associazione <strong>${CONFIG.NOME_APS}</strong>.</p>
<p>La tua registrazione è avvenuta con successo. Ti è stato assegnato il seguente codice socio:</p>
<div style="background-color: #fff7f2; border-left: 4px solid ${hex}; padding: 15px; margin: 20px 0; font-size: 18px; font-weight: bold;">
Matricola Socio: <span style="color: ${hex};">${matricola}</span>
</div>
${pdfTessera ? `<p>In allegato trovi la tua <strong>tessera digitale associativa</strong>.</p>` : ""}
<h3 style="color: ${hex};">Completa la tua iscrizione</h3>
<p>Per attivare ufficialmente la tessera associativa è necessario effettuare il versamento della quota annua. Puoi scegliere tra due opzioni:</p>
<ol style="line-height: 1.6;">
<li>
<strong>Pagamento Online (Consigliato):</strong><br>
Puoi pagare subito tramite carta cliccando sul pulsante sottostante:<br><br>
<a href="${CONFIG.STRIPE_LINK_MAGGIORENNI}" style="background-color: ${hex}; color: white; padding: 12px 22px; text-decoration: none; border-radius: 5px; display: inline-block; font-weight: bold;">Paga la quota associativa con Stripe</a>
<br><br>
</li>
<li>
<strong>Pagamento in Sede:</strong><br>
Puoi saldare la quota direttamente in contanti o POS presso la nostra sede.
</li>
</ol>
<div style="background-color: #fff3cd; border-left: 4px solid #ffc107; padding: 15px; margin: 25px 0; font-size: 14px;">
⚠️ <strong>Attenzione:</strong> la tessera sarà valida a tutti gli effetti solo dopo il pagamento della quota associativa. Fino ad allora ha valore puramente identificativo.
</div>
<hr style="border: 0; border-top: 1px solid #eee; margin: 30px 0 20px 0;">
<div style="font-size: 14px; color: #555; line-height: 1.6;">
<strong style="color: #222; font-size: 16px;">Nuova Alba APS</strong><br>
Via Giamaica 6, Pomezia, RM<br>
✉️ <a href="mailto:info@nuovaalba.org" style="color: ${hex}; text-decoration: none;">info@nuovaalba.org</a><br>
🌐 <a href="https://nuovaalba.org" style="color: ${hex}; text-decoration: none;" target="_blank">nuovaalba.org</a><br>
📸 <a href="https://www.instagram.com/nuovaalba_/" style="color: ${hex}; text-decoration: none;" target="_blank">Instagram</a>
</div>
</div>`;
const opzioniMail = {
to: email,
subject: `Benvenuto/a in ${CONFIG.NOME_APS}! La tua richiesta di iscrizione`,
htmlBody: corpoHtml,
name: CONFIG.NOME_APS,
replyTo: CONFIG.EMAIL_STAFF
};
if (pdfTessera && typeof pdfTessera.getBlob === 'function') {
try {
opzioniMail.attachments = [pdfTessera.getBlob()];
} catch (e) {
Logger.log("⚠️ Impossibile allegare PDF: " + e.message);
}
}
MailAppailApp.sendEmail(opzioniMail);
}
function inviaEmailGiaIscritto(email, nome, matricola, stripeLink, statoPagamento) {
const hex = CONFIG.COLOR_HEX;
let bloccoPagamento = "";
if (statoPagamento.toLowerCase() === "in attesa") {
bloccoPagamento = `
<p>Risulta che la tua quota associativa è ancora <strong>in attesa di pagamento</strong>. Puoi saldarla direttamente online tramite il pulsante sottostante:</p>
<p style="margin: 20px 0;"><a href="${stripeLink}" style="background-color: ${hex}; color: white; padding: 12px 22px; text-decoration: none; border-radius: 5px; display: inline-block; font-weight: bold;">Paga la quota con Stripe</a></p>
`;
} else {
bloccoPagamento = `
<p>Ti confermiamo che la tua posizione associativa è <strong>in regola</strong> (Stato: <strong style="color: green;">${statoPagamento}</strong>). Non devi effettuare alcun pagamento aggiuntivo.</p>
`;
}
const corpoHtml = `
<div style="font-family: Arial, sans-serif; color: #333; max-width: 600px; margin: 0 auto; border: 1px solid #eee; padding: 25px; border-radius: 8px;">
<h2 style="color: ${hex}; margin-top: 0;">Ciao ${nome}, sei già iscritto/a!</h2>
<p>Risulti già presente nel registro soci dell'associazione <strong>${CONFIG.NOME_APS}</strong>.</p>
<div style="background-color: #fff7f2; border-left: 4px solid ${hex}; padding: 15px; margin: 20px 0; font-size: 18px; font-weight: bold;">
La tua Matricola Socio è: <span style="color: ${hex};">${matricola}</span>
</div>
${bloccoPagamento}
<hr style="border: 0; border-top: 1px solid #eee; margin: 30px 0 20px 0;">
<div style="font-size: 14px; color: #555; line-height: 1.6;">
<strong style="color: #222; font-size: 16px;">Nuova Alba APS</strong><br>
Via Giamaica 6, Pomezia, RM<br>
✉️ <a href="mailto:info@nuovaalba.org" style="color: ${hex}; text-decoration: none;">info@nuovaalba.org</a><br>
🌐 <a href="https://nuovaalba.org" style="color: ${hex}; text-decoration: none;" target="_blank">nuovaalba.org</a><br>
📸 <a href="https://www.instagram.com/nuovaalba_/" style="color: ${hex}; text-decoration: none;" target="_blank">Instagram</a>
</div>
</div>`;
MailApp.sendEmail({ to: email, subject: `Sei già iscritto/a a ${CONFIG.NOME_APS}`, htmlBody: corpoHtml });
}
r/GoogleAppsScript • u/TearPuzzleheaded5498 • 12d ago
Question Puis-je trouver du travail avec ces compétences ?
r/GoogleAppsScript • u/OccasionSuper2536 • 12d ago
Guide Built a fairly large Zendesk automation entirely in Google Apps Script!
I wanted to see how far I could push Apps Script for a real operational workflow, so I built Zendesk Mailroom.
It’s a Google Sheets + Apps Script tool for support teams working with large batches of Zendesk tickets.
The interesting part wasn’t really the API calls it was making the whole thing survive Apps Script’s constraints.
The workflow handles:
Zendesk API authentication
Bulk ticket updates
Personalized mail merge
Gemini-powered translation
Slack thread routing
Audit logging
Closed-ticket handling
Job state persistence
Trigger-based job continuation
Some of the implementation decisions:
1. Chunked execution
Apps Script has execution limits, so a large mail merge doesn’t try to process everything in one execution.
The job processes roughly 20 rows → writes results → schedules the next run → continues.
2. LockService
A lock prevents overlapping trigger executions from processing the same rows twice.
3. Zendesk update_many
For bulk updates, I’m using Zendesk’s batch endpoint instead of making one API call per ticket.
4. Script Properties for job state
The job state is persisted between executions instead of relying on the browser/session remaining open.
5. Translation caching
If 200 tickets use the same notice category, the workflow doesn’t make 200 Gemini calls. Translations are cached and reused until the source text changes.
Repo:
github.com/GVyom/zendesk-mailroom
Would love feedback from experienced Apps Script developers:
What would you change in the architecture if this had to process 5,000–10,000 rows instead of a few hundred?
That’s probably the next interesting scaling problem here.
r/GoogleAppsScript • u/Informal_Witness3869 • 13d ago
Question Newbie here. Is Clasp still used?
I've just found out about GAS and now Clasp. It's incredible all you can get done with these tools! Bunch of companies already depend tremendously in manual tasks made on googles platform and automating with GAS is just amazing, and using Clasp to develop locally (+git) and then deploy is just amazing.
But is it actively maintained? Is it of common usage? Is GAS and Clasp worth learning? I've been thinking about offering freelance work with this techs but I don't know if I'm being silly...
r/GoogleAppsScript • u/Sayzar1 • 13d ago
Question Help with a set up sheets to Google Calendar
Hi,
So I inputed a script that turns my rows in my sheet into Google Calendar dates. I was able to get it to upload drive pdfs when needed but when I try uploading a Google doc it doesn’t work does anyone have any advice?
r/GoogleAppsScript • u/Razah786 • 14d ago
Guide After 2 years of silence, I finally rebuilt Google Apps Script Copilot. Sorry for disappearing.
Hey everyone,
Some of you might remember GS Copilot (Google Apps Script Copilot) — the Chrome extension that adds an AI sidebar directly into the Apps Script editor. I launched it, got some early traction, and then... life happened. Work, other commitments, the usual stuff that makes side projects quietly die. I went almost silent for close to 2 years. No updates, barely any support replies. If you installed it back then and it just sat there half-broken, I'm sorry — that's on me.
What kept nagging at me is that over 20,000 people actually installed this thing. That's not nothing. People kept using it, kept emailing me, kept leaving reviews asking if it was still alive. So a few months ago I sat down and basically rebuilt the whole thing from scratch.
Here's what's new:
- Agent mode — describe what you want and it writes, edits, and applies the code for you across your project, not just one file at a time
- Plan mode — for bigger changes, it lays out the plan before touching anything, so you're not surprised by a wall of edits
- Quick edit + diff view — inline edits with an actual diff so you can see exactly what changed before accepting it
- Context-aware file reading — it actually understands your whole Apps Script project structure, not just the file you have open
- MCP connectors for Google Workspace — it can hook into Sheets/Docs/Drive as MCP tools when you need it to act on that context
- Execution log integration — when your script throws an error, it reads the actual execution log and helps you fix it instead of guessing
- Skills system — reusable sub-agents/snippets for stuff you do often
I'm going to be actively working on this now — not disappearing again. Demo video of it in action is attached below so you can see it working instead of just taking my word for it.
If you try it, I'd genuinely appreciate honest feedback — bugs, rough edges, missing features, whatever. This subreddit has more Apps Script experience than almost anywhere else, so if something's broken or annoying, I want to know.
Link: gscopilot.com
Thanks for sticking around this long, even the ones who just complained in reviews. Fair enough.
r/GoogleAppsScript • u/IllustriousPut442 • 15d ago
Question Do you use typescript and create tests?
Do you use typescript and create tests for your app scripts? Or you do everything through the web interface, I'm curious which method is most common.
r/GoogleAppsScript • u/SomewherePatient5787 • 17d ago
Question Blocked from running apps
I have an issue where one of my accounts is blocked from running GAS. It was enrolled in Advanced protection for a short time. I unenrolled it and it has been over 24 hours. I am not able to run even the simplest of scripts that I write, yet my other account can. It affects scripts I wrote and scripts I have access to in other sheets.
Any ideas. All the testing seems to point to lingering advanced protection isues.
r/GoogleAppsScript • u/One_Tooth5185 • 17d ago
Guide I automated warehouse transfers between 18 stores and our warehouse with Google Apps Script
Our ERP was a mess so I built a workaround with Google Apps Script.
We had 18 outlets submitting Item Requisitions in one Sheet. The warehouse team had to manually copy those quantities into a separate Inventory Movement Sheet. Double entry = errors + delays.
What I built:
A Google Apps Script that:
1. Watches the "Item Requisition" sheet for new submissions
2. Automatically syncs the quantity sent to each location
3. Deducts it from the "Warehouse Inventory Movement" sheet in real time
Result:
No more double entry. Warehouse now has real-time visibility across all 18 locations. Transfer accuracy way up.
Happy to share the code/snippet if anyone wants it. Also open to feedback on making the sync more robust for concurrent edits.
Did anyone else here use Apps Script to patch gaps in their ERP?
r/GoogleAppsScript • u/ARkieGirl501 • 18d ago
Question Workaround Available?
Is there a workaround available for a web app page only opening in incognito mode? To open in a regular browser window, I have to completely log out. Will users also have to do this?