Come Creare uno Scadenzario Online con Google Sheets e Notifiche Email Automatiche

Quante volte ti è capitato di dimenticare una bolletta in scadenza o di pagare in ritardo il bollo auto? Se la risposta è “troppe”, sei nel posto giusto.

In questa guida ti mostrerò come creare uno scadenzario online completamente gratuito usando Google Fogli (Google Sheets), con un sistema di notifiche email automatiche che ti avviserà in anticipo di ogni pagamento in arrivo.

Non servono competenze tecniche particolari: ti guiderò passo dopo passo.

Scheda del progetto:

  • ⏱️ Tempo di lettura: 10 minuti
  • 🤓 Difficoltà: Facile
  • 💰 Costo: Gratuito

Cosa otterrai alla fine di questa guida

  • ✅ Un foglio di calcolo online accessibile da smartphone e PC.
  • ✅ Un sistema di colori automatico che evidenzia le scadenze urgenti.
  • ✅ Email giornaliere automatiche con il riepilogo delle scadenze.
  • ✅ Un menu personalizzato per gestire tutto con un clic.

Requisiti

Per seguire questa guida ti serve solo:

  • Un account Google (Gmail).
  • 10-15 minuti di tempo.
  • Un computer (consigliato per la configurazione iniziale).

Passo 1: Crea il Foglio Google

Iniziamo creando la base del nostro scadenzario:

  1. Vai su sheets.google.com.
  2. Clicca sul pulsante “+” per creare un nuovo foglio vuoto.
  3. Rinomina il file in alto a sinistra in “Scadenzario”.

Ora impostiamo la struttura. Nella prima riga (riga 1), inserisci queste intestazioni nelle rispettive colonne:

ColonnaIntestazione
AID
BDescrizione
CCategoria
DData Scadenza
EImporto €
FStato
GGiorni Rimanenti
HNote

Consiglio: Seleziona tutta la riga 1 e rendila in grassetto (Ctrl+B) per distinguerla dai dati. Blocca la prima riga andando su Visualizza → Blocca → 1 riga.


Passo 2: Formatta le Colonne

Per rendere il foglio funzionale e professionale, formattiamo i dati correttamente.

1. Formattare la Data (Colonna D)

  1. Clicca sulla lettera “D” in alto per selezionare tutta la colonna.
  2. Vai su Formato → Numero → Data.

2. Formattare la Valuta (Colonna E)

  1. Clicca sulla lettera “E” per selezionare la colonna.
  2. Vai su Formato → Numero → Valuta.

3. Creare un menu a tendina per lo Stato (Colonna F)

Questa funzione ti permette di cambiare lo stato del pagamento velocemente.

  1. Seleziona le celle da F2 a F100.
  2. Vai su Dati → Convalida dati.
  3. Clicca su “Aggiungi regola”.
  4. In “Criteri” seleziona “Menu a discesa”.
  5. Aggiungi queste opzioni:
    • Da Pagare
    • Pagato
    • Scaduto
    • In Sospeso
  6. Clicca su “Fine”.

Passo 3: Aggiungi la Formula per i Giorni Rimanenti

Vogliamo che il foglio calcoli automaticamente quanti giorni mancano.

Clicca sulla cella G2 e incolla questa formula:

Excel

=SE(D2="";"";SE(F2="Pagato";"✓ Pagato";D2-OGGI()))

Premi Invio. Poi trascina la formula verso il basso (o copia G2 e incollala nelle celle sottostanti).

  • Come funziona: Se la scadenza è passata, vedrai un numero negativo. Se lo stato è “Pagato”, apparirà una spunta ✓.

Passo 4: Colori Automatici (Formattazione Condizionale)

Facciamo in modo che il foglio ci avvisi visivamente colorando le celle in base all’urgenza.

  1. Seleziona la colonna G.
  2. Vai su Formato → Formattazione condizionale.
  3. Aggiungi le seguenti 4 regole (clicca su “Aggiungi un’altra regola” per ognuna):
  • 🔴 Scaduto: Se Minore di 0 → Sfondo Rosso.
  • 🟠 Urgente: Se È compreso tra 0 e 7 → Sfondo Arancione.
  • 🟡 Attenzione: Se È compreso tra 8 e 30 → Sfondo Giallo.
  • 🟢 Tranquillo: Se Maggiore di 30 → Sfondo Verde.

Passo 5: Lo Script per le Email Automatiche

Questa è la parte più potente. Useremo un piccolo script (codice) che controllerà il foglio ogni mattina e ti invierà un’email se ci sono scadenze.

5.1 Apri l’Editor

  1. Nel foglio, vai su Estensioni → Apps Script.
  2. Si aprirà una nuova scheda. Cancella tutto il codice presente.

5.2 Copia il Codice

Copia e incolla questo intero blocco di codice:

JavaScript

/**
 * SCADENZARIO CON NOTIFICHE EMAIL
 * ================================
 * Modifica la tua email qui sotto!
 */

// ⚠️ IMPORTANTE: Sostituisci con la TUA email
const EMAIL_DESTINATARIO = "tua-email@gmail.com";

// Configurazione (puoi modificare questi valori)
const NOME_FOGLIO = "Foglio1";  // Nome del foglio (di solito "Foglio1")
const ORA_INVIO = 8;            // Ora di invio email (0-23)

/**
 * Crea il menu personalizzato
 */
function onOpen() {
  SpreadsheetApp.getUi()
    .createMenu('📅 Scadenzario')
    .addItem('📧 Invia Report Email Ora', 'inviaReportManuale')
    .addItem('🔔 Controlla Scadenze', 'controllaEMostraRiepilogo')
    .addSeparator()
    .addItem('⚙️ Attiva Notifiche Giornaliere', 'attivaTrigger')
    .addItem('❌ Disattiva Notifiche', 'disattivaTrigger')
    .addSeparator()
    .addItem('🎨 Aggiorna Colori', 'aggiornaColori')
    .addToUi();
}

/**
 * Analizza tutte le scadenze
 */
function analizzaScadenze() {
  const foglio = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(NOME_FOGLIO);
  if (!foglio) {
    SpreadsheetApp.getUi().alert('❌ Errore: Foglio "' + NOME_FOGLIO + '" non trovato!');
    return null;
  }
  
  const dati = foglio.getDataRange().getValues();
  const oggi = new Date();
  oggi.setHours(0, 0, 0, 0);
  
  const risultati = {
    scadute: [],
    urgenti: [],    // 0-7 giorni
    imminenti: [],  // 8-30 giorni
    ok: []          // oltre 30 giorni
  };
  
  for (let i = 1; i < dati.length; i++) {
    const riga = dati[i];
    const descrizione = riga[1];
    const categoria = riga[2];
    const dataScadenza = riga[3];
    const importo = riga[4] || 0;
    const stato = riga[5];
    const note = riga[7];
    
    // Salta righe vuote o già pagate
    if (!dataScadenza || stato === 'Pagato') continue;
    
    const data = new Date(dataScadenza);
    data.setHours(0, 0, 0, 0);
    const giorniRimanenti = Math.ceil((data - oggi) / (1000 * 60 * 60 * 24));
    
    const scadenza = {
      riga: i + 1,
      descrizione: descrizione || 'Senza descrizione',
      categoria: categoria || '-',
      dataScadenza: Utilities.formatDate(data, 'Europe/Rome', 'dd/MM/yyyy'),
      importo: importo,
      giorni: giorniRimanenti,
      note: note || ''
    };
    
    if (giorniRimanenti < 0) {
      risultati.scadute.push(scadenza);
      // Aggiorna stato nel foglio
      foglio.getRange(i + 1, 6).setValue('Scaduto');
    } else if (giorniRimanenti <= 7) {
      risultati.urgenti.push(scadenza);
    } else if (giorniRimanenti <= 30) {
      risultati.imminenti.push(scadenza);
    } else {
      risultati.ok.push(scadenza);
    }
  }
  
  return risultati;
}

/**
 * Invia email con report scadenze
 */
function inviaEmailReport() {
  const risultati = analizzaScadenze();
  if (!risultati) return;
  
  const { scadute, urgenti, imminenti } = risultati;
  
  // Invia email solo se ci sono scadenze rilevanti
  if (scadute.length === 0 && urgenti.length === 0 && imminenti.length === 0) {
    Logger.log('Nessuna scadenza da segnalare');
    return;
  }
  
  // Crea oggetto email
  let oggetto = '📅 Scadenzario: ';
  if (scadute.length > 0) oggetto += `🔴 ${scadute.length} scadute `;
  if (urgenti.length > 0) oggetto += `🟠 ${urgenti.length} urgenti `;
  if (imminenti.length > 0) oggetto += `🟡 ${imminenti.length} in arrivo`;
  
  // Crea corpo email HTML
  const dataOggi = Utilities.formatDate(new Date(), 'Europe/Rome', 'dd/MM/yyyy HH:mm');
  const urlFoglio = SpreadsheetApp.getActiveSpreadsheet().getUrl();
  
  let html = `
    <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
      <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 25px; border-radius: 10px 10px 0 0; text-align: center;">
        <h1 style="margin: 0; font-size: 24px;">📅 Report Scadenzario</h1>
        <p style="margin: 10px 0 0 0; opacity: 0.9;">${dataOggi}</p>
      </div>
      <div style="background: #f9fafb; padding: 20px; border-radius: 0 0 10px 10px;">
  `;
  
  // Sezione Scadute
  if (scadute.length > 0) {
    html += creaSezioneEmail('🔴 SCADENZE SCADUTE', scadute, '#fee2e2', '#dc2626');
  }
  
  // Sezione Urgenti
  if (urgenti.length > 0) {
    html += creaSezioneEmail('🟠 Urgenti (entro 7 giorni)', urgenti, '#ffedd5', '#ea580c');
  }
  
  // Sezione Imminenti
  if (imminenti.length > 0) {
    html += creaSezioneEmail('🟡 In arrivo (entro 30 giorni)', imminenti, '#fef9c3', '#ca8a04');
  }
  
  // Riepilogo importi
  const totScadute = scadute.reduce((s, x) => s + x.importo, 0);
  const totUrgenti = urgenti.reduce((s, x) => s + x.importo, 0);
  const totImminenti = imminenti.reduce((s, x) => s + x.importo, 0);
  const totale = totScadute + totUrgenti + totImminenti;
  
  html += `
    <div style="background: white; padding: 20px; border-radius: 8px; margin-top: 20px;">
      <h3 style="margin-top: 0; color: #374151;">💰 Riepilogo Importi</h3>
      <table style="width: 100%;">
        <tr><td>Scadute:</td><td style="text-align: right; color: #dc2626; font-weight: bold;">€ ${totScadute.toFixed(2)}</td></tr>
        <tr><td>Urgenti:</td><td style="text-align: right; color: #ea580c; font-weight: bold;">€ ${totUrgenti.toFixed(2)}</td></tr>
        <tr><td>In arrivo:</td><td style="text-align: right; color: #ca8a04; font-weight: bold;">€ ${totImminenti.toFixed(2)}</td></tr>
        <tr style="border-top: 2px solid #e5e7eb;"><td><strong>TOTALE:</strong></td><td style="text-align: right; font-size: 20px; font-weight: bold;">€ ${totale.toFixed(2)}</td></tr>
      </table>
    </div>
    
    <div style="text-align: center; margin-top: 25px;">
      <a href="${urlFoglio}" style="display: inline-block; background: #667eea; color: white; padding: 12px 30px; text-decoration: none; border-radius: 5px; font-weight: bold;">📋 Apri Scadenzario</a>
    </div>
    
    <p style="text-align: center; color: #9ca3af; font-size: 12px; margin-top: 30px;">
      Email automatica generata dal tuo Scadenzario Google Sheets
    </p>
      </div>
    </div>
  `;
  
  // Invia email
  try {
    MailApp.sendEmail({
      to: EMAIL_DESTINATARIO,
      subject: oggetto,
      htmlBody: html
    });
    Logger.log('Email inviata a: ' + EMAIL_DESTINATARIO);
  } catch (e) {
    Logger.log('Errore invio email: ' + e.toString());
  }
}

/**
 * Crea sezione HTML per email
 */
function creaSezioneEmail(titolo, scadenze, bgColor, borderColor) {
  let html = `
    <div style="background: ${bgColor}; border-left: 4px solid ${borderColor}; padding: 15px; border-radius: 8px; margin-bottom: 15px;">
      <h3 style="margin: 0 0 15px 0; color: #1f2937;">${titolo} (${scadenze.length})</h3>
      <table style="width: 100%; background: white; border-radius: 5px; border-collapse: collapse;">
        <tr style="background: #f3f4f6;">
          <th style="padding: 10px; text-align: left;">Descrizione</th>
          <th style="padding: 10px; text-align: left;">Scadenza</th>
          <th style="padding: 10px; text-align: right;">Importo</th>
        </tr>
  `;
  
  scadenze.forEach(s => {
    const giorniTesto = s.giorni < 0 ? `${Math.abs(s.giorni)} giorni fa` : (s.giorni === 0 ? 'OGGI!' : `tra ${s.giorni} giorni`);
    html += `
      <tr style="border-bottom: 1px solid #e5e7eb;">
        <td style="padding: 10px;"><strong>${s.descrizione}</strong><br><small style="color: #6b7280;">${s.categoria}</small></td>
        <td style="padding: 10px;">${s.dataScadenza}<br><small style="color: #6b7280;">${giorniTesto}</small></td>
        <td style="padding: 10px; text-align: right; font-weight: bold;">€ ${s.importo.toFixed(2)}</td>
      </tr>
    `;
  });
  
  html += '</table></div>';
  return html;
}

/**
 * Attiva notifiche giornaliere
 */
function attivaTrigger() {
  // Rimuovi trigger esistenti
  disattivaTrigger();
  
  // Crea nuovo trigger
  ScriptApp.newTrigger('inviaEmailReport')
    .timeBased()
    .atHour(ORA_INVIO)
    .everyDays(1)
    .create();
  
  SpreadsheetApp.getUi().alert(
    '✅ Notifiche Attivate!',
    'Riceverai un\'email ogni giorno alle ore ' + ORA_INVIO + ':00 circa.\n\nEmail: ' + EMAIL_DESTINATARIO,
    SpreadsheetApp.getUi().ButtonSet.OK
  );
}

/**
 * Disattiva notifiche
 */
function disattivaTrigger() {
  const triggers = ScriptApp.getProjectTriggers();
  triggers.forEach(trigger => {
    if (trigger.getHandlerFunction() === 'inviaEmailReport') {
      ScriptApp.deleteTrigger(trigger);
    }
  });
}

/**
 * Invia report manualmente
 */
function inviaReportManuale() {
  inviaEmailReport();
  SpreadsheetApp.getUi().alert('📧 Email inviata a: ' + EMAIL_DESTINATARIO);
}

/**
 * Mostra riepilogo in popup
 */
function controllaEMostraRiepilogo() {
  const risultati = analizzaScadenze();
  if (!risultati) return;
  
  const { scadute, urgenti, imminenti, ok } = risultati;
  const totale = [...scadute, ...urgenti, ...imminenti].reduce((s, x) => s + x.importo, 0);
  
  let msg = '📊 RIEPILOGO SCADENZE\n\n';
  msg += `🔴 Scadute: ${scadute.length}\n`;
  msg += `🟠 Urgenti (≤7 gg): ${urgenti.length}\n`;
  msg += `🟡 In arrivo (≤30 gg): ${imminenti.length}\n`;
  msg += `🟢 OK (>30 gg): ${ok.length}\n\n`;
  msg += `💰 Totale da pagare: € ${totale.toFixed(2)}`;
  
  SpreadsheetApp.getUi().alert('Riepilogo Scadenze', msg, SpreadsheetApp.getUi().ButtonSet.OK);
}

/**
 * Aggiorna formattazione condizionale
 */
function aggiornaColori() {
  const foglio = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(NOME_FOGLIO);
  if (!foglio) return;
  
  const ultimaRiga = Math.max(foglio.getLastRow(), 10);
  const range = foglio.getRange(2, 7, ultimaRiga - 1, 1); // Colonna G
  
  const regole = [
    SpreadsheetApp.newConditionalFormatRule()
      .whenNumberLessThan(0)
      .setBackground('#fecaca').setFontColor('#991b1b')
      .setRanges([range]).build(),
    SpreadsheetApp.newConditionalFormatRule()
      .whenNumberBetween(0, 7)
      .setBackground('#fed7aa').setFontColor('#9a3412')
      .setRanges([range]).build(),
    SpreadsheetApp.newConditionalFormatRule()
      .whenNumberBetween(8, 30)
      .setBackground('#fef08a').setFontColor('#854d0e')
      .setRanges([range]).build(),
    SpreadsheetApp.newConditionalFormatRule()
      .whenNumberGreaterThan(30)
      .setBackground('#bbf7d0').setFontColor('#166534')
      .setRanges([range]).build()
  ];
  
  foglio.setConditionalFormatRules(regole);
  SpreadsheetApp.getUi().alert('🎨 Colori aggiornati!');
}

5.3 Configura la tua Email

Cerca la riga numero 8 nel codice appena incollato:

const EMAIL_DESTINATARIO = "tua-email@gmail.com";

Modifica tua-email@gmail.com inserendo il tuo indirizzo reale.

5.4 Salva ed Esegui

  1. Clicca sull’icona Salva (💾).
  2. Assicurati che nel menu a tendina in alto sia selezionato onOpen.
  3. Clicca su ▶️ Esegui.
  4. Google ti chiederà le autorizzazioni: clicca su Esamina autorizzazioni → Scegli account → Avanzate → Vai a Scadenzario (non sicuro) → Consenti.

Nota: L’avviso “non sicuro” appare perché sei tu lo sviluppatore dello script. È perfettamente sicuro dato che il codice lo hai inserito tu!


Passo 6: Attiva il sistema

Torna sulla scheda del foglio di calcolo e ricarica la pagina (F5).

Dopo qualche secondo, vedrai apparire un nuovo menu in alto chiamato “📅 Scadenzario”.

Clicca su: 📅 Scadenzario → ⚙️ Attiva Notifiche Giornaliere.

🎉 Fatto! Ogni mattina alle 8:00 il sistema controllerà le scadenze e ti invierà una mail se c’è qualcosa da pagare.


FAQ: Problemi comuni

L’email non arriva?

Controlla la cartella Spam. Se non c’è, prova a inviarla manualmente dal menu: Scadenzario → Invia Report Email Ora.

Come lo uso da smartphone?

Scarica l’app Google Fogli. Puoi vedere e modificare i dati ovunque. Le email automatiche partiranno comunque perché girano sui server Google, non sul tuo telefono.

È sicuro inserire i miei dati?

Sì, i dati rimangono nel tuo account Google privato, protetti dalla stessa sicurezza di Gmail e Drive.

Lascia un commento

⚙️ Cookie