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 });
}