JavaScript, HTML, CSS e... !
34 commenti

Inviare una mail in modo automatico alla scadenza del servizio

Creare un sistema di avviso scadenze in Google Apps Script

Con Google Apps Script è possibile creare un semplice applicativo fai da te per il controllo giornaliero e l'invio di una mail di notifica relativa ad una particolare scadenza, ad esempio notificare ad un cliente o ad un fornitore la scadenza di un servizio.

Per farlo basterà avvalersi di uno Spreadsheet, dove sarà presente la lista dei contatti e le correlate date di scadenza, e di poche righe di codice in Apps Script da inserire nell'editor di script associato al foglio di calcolo (bound-script).

Un'ipotetica tabella dei contatti potrebbe essere la seguente, Fig. 1 (a scopo illustrativo ho inserito 3 nomi ed altrettanti indirizzi mail di fantasia):



tabella dei contatti in uno spreadsheet

Fig. 1 - Esempio di una lista contatti in uno Spreadsheet


Il codice da inserire nell'editor di script, dal menu 'Strumenti -> Editor di script', è il seguente:

function alertSender() {
  var today = new Date(); // es: 2018/03/30 (il formato effettivo della data sarà in 'full text string format')
  var values = SpreadsheetApp.getActiveSheet().getDataRange().getValues();
  for(n=1;n<values.length;++n){
    var cell_date = values[n][2];
    var expired = today > cell_date;
    if (expired) {
      MailApp.sendEmail(values[n][1], 'Mail automatica', 'Servizio scaduto per il sig. ' + values[n][0]);
      Logger.log('Mail inviata all\'indirizzo ' + values[n][1] + ' del sig. ' + values[n][0]);
    }
  }
}

A questo punto, al fine di eseguire giornalmente il controllo delle scadenze ed il conseguente eventuale invio della mail di notifica, sarà necessario impostare un apposito trigger. Dal menu 'Modifica', dell'editor di script, selezionare la voce 'Trigger del progetto corrente' ed inserire un nuovo attivatore che preveda l'esecuzione della nostra funzione, nel caso specifico 'alertSender', con evento basato sul tempo a cadenza giornaliera in un range di orario desiderato, potrebbe essere ideale dalle 7:00 alle 8:00 di mattina.

Il log, inserito al solo scopo illustrativo, mostrerà nel caso specifico dell'esempio in questione, il seguente risultato, Fig. 3:



log di apps script

Fig. 3 - Esempio del risultato nel log di Apps Script


Inutile dire che il sistema può essere adattato alle più svariate esigenze, così come la mail di notifica può essere fatta arrivare anche, o solo, al proprio indirizzo mail per prendere prima in carico la segnalazione.

A tal proposito, informazioni aggiuntive su come arricchire il funzionamento di questo applicativo continuano nel mio libro "Punta in alto con... Google Apps Script":



punta in alto con google apps script - creare un sistema di scadenze

Fig. 4 - Il libro in italiano - Punta in alto con... Google Apps Script - pag 136 e 137


Troverai altre informazioni utili per la creazione di questo applicativo:

- trigger semplici;
- trigger installabili;
- gestione dell'onOpen() e dell'onEdit();
- notifiche;
- uso della classe TriggerBuilder;
- gestione degli attivatori;
- l'hub per gli sviluppatori della G Suite;
- molti altri accorgimenti per l'ottimizzazione degli script.

...E QUESTO È SOLO QUANTO RIFERITO ALL'AUTOMATIZZAZIONE DI PROCESSI IN APPS SCRIPT!

ACQUISTA ORA IL LIBRO SU AMAZON:

punta in alto con google apps script libro italiano

Se sei pronto a diventare un esperto nella programmazione in Google Apps Script non posso fare altro che augurarti una buona lettura e soprattutto... Buon divertimento!

Lo script necessita l'abilitazione dei Servizi Avanzati di Google per le Sheet API, fare fede all'articolo 'Abilitare l'uso delle API dei Servizi Avanzati nei progetti in Google Apps Script'.
Al primo avvio dello script (che conviene effettuare manualmente) verranno richiesti i permessi relativi allo Sheet ed a Mail, per la procedura fare fede all'articolo 'Flusso per l'Autorizzazione dei Google Services nei progetti in Apps Script'.

Tags

Michele Pisani

Michele Pisani

Sviluppatore Javascript ed esperto in Digital Analytics

L'esperienza nel settore Digital Analytics unita ad anni di sviluppo in Javascript ha trovato la massima espressione in Google Apps Script che mi ha permesso, con estrema facilità e poche righe di codice, di realizzare potenti applicazioni interattive e processi automatizzati integrati con i prodotti della G Suite.

Come contattarmi
scrivi un commento

34 Commenti

  1. Friday, August 24, 2018 alle ore 21:38 marco

    buona sera
    inizio adesso ad usare lo sheets google, che contiene la funzione GOOGLEFINANCE, che voglio usare per scaricare le quotazioni dei titoli e quindi costruire dei grafici, per poter trovare in auto quelli più idonei ad aprire un asset.
    Detto ciò, il problema è che il trigger a tempo regolato a minuto, non scatta.
    Per vedere se funziona ho messo là quattro righe

    function incrementa() {
    var conta1=0;
    var spreadsheet = SpreadsheetApp.getActive();
    spreadsheet.getRange('b2').activate();
    conta1=spreadsheet.getCurrentCell().getValue();
    conta1=conta1+1;
    spreadsheet.getCurrentCell().setValue(conta1);
    };


    e chiaramente attivato il trigger a minuto, che punta alla function.
    Ma la cella B2 non viene incrementata (ogni minuto), cosa che accade invece se lancio la function a mano.
    Il servizio google sheets API è attivo, così come nella console API google(dice API abilitata).
    Che ho tralasciato?
    Grazie per un eventuale interessamento

    Rispondi a questo commento
    • Saturday, August 25, 2018 alle ore 00:48 Michele PisaniAutore

      Ciao marco,
      il tuo script non sembra avere niente che non va. L'ho testato ed ho assegnato un trigger basato su tempo che esegue ogni minuto la funzione 'incrementa' e la cella viene correttamente incrementata ogni minuto (per questo tipo di operazioni inoltre non è necessario abilitare le Google Sheets API).

      Quello che puoi provare a fare è eliminare quel trigger e crearne uno nuovo.

      Se il problema dovesse persistere puoi provare a creare uno script autonomo (standalone) e richiamare lo Spreadsheet anziché con SpreadsheetApp.getActive(); con il seguente metodo:

      var spreadsheet = SpreadsheetApp.openById("SPREADSHEET_ID");
      var sheet = SpreadsheetApp.setActiveSheet(spreadsheet.getSheets()[0]);


      Dove SPREADSHEET_ID è ovviamente l'id del Foglio di Google su cui lavori e getSheets()[0] indica il primo foglio del file.

      Rispondi a questo commento
      • Saturday, August 25, 2018 alle ore 13:53 marco

        grazie per la risposta
        effettivamente è bastato richiamare lo spreadsheet attraverso il suo ID e il problema si è risolto.
        La cosa che non sapevo è che l'ID è un codice lunghissimo, che ho ricavato mediante

        var Idspreadsheet=spreadsheet.getId();



        A scopo informativo, aggiungo che con la funzione GOOGLEFINANCE, si può costruire una tabella dei prezzi di una lista di titoli con precisione di 1 minuto, quindi bisogna lasciare il programma al lavoro per accumulare abbastanza dati.
        Fino a qualche settimana fa si poteva usare una riga tipo questa

        https://www.google.com/finance/getprices?q=RACE&x=BIT&i=60&p=5d&f=d,c,o,h,l&df=cpct&auto=1&ts=1266701290218



        che restituiva una pagina con i prezzi del titolo ferrari(RACE), con il prezzo di apertura e chiusura di ogni singolo minuto, anche per un intera giornata.
        Peccato che adesso non funziona più!
        Restituisce

        We're sorry... but your computer or network may be sending automated queries. To protect our users, we can't process your request right now.
        ma questa è un'altra storia



      • Saturday, August 25, 2018 alle ore 16:59 Michele PisaniAutore

        Ciao marco,
        mi fa piacere che sei riuscito a risolvere e grazie per l'approfondimento su quella funzione integrata dei Fogli di Google.
        Giusto per informazione, l'id dello Spreadsheet che hai ottenuto con .getId() è lo stesso presente direttamente nell'URL dello Spreadsheet.

  2. Tuesday, November 6, 2018 alle ore 07:29 Luca

    Ho provato la funzione ed è tutto ok. L'ho un po adattata alla mia esigenza ma anche se ho impostato il trigger non viene richiamata.
    È dovuto al fatto che la funzione punta al file aperto? Mi riferisco al getActivesheet.
    Come posso farla puntate ad uno specifico file e nel dettaglio ad uno specifico sheet di quel file?
    Grazie mille

    Rispondi a questo commento
  3. Thursday, December 6, 2018 alle ore 18:28 Marco75

    Buonasera Michele,
    io ho modificato con l'aiuto di un amico lo script per poter formattare la mail generata secondo mia
    esigenza, ma da Gsuite la mail viene rimbalzata e non la consegna al destinatario, dalla Gmail
    tradizionale invece funziona tutto correttamente, il supporto di Google Cloud mi ha detto di chiedere
    a lei se ha qualche idea in merito.
    Help please grazie.

    function alertSender() {
    var today = new Date();
    var values = SpreadsheetApp.getActiveSheet().getDataRange().getValues();
    for(n=1;n<values.length;++n){
    var cell_date = values[n][2];
    var expired = today > cell_date;
    if (expired) {
    //MailApp.sendEmail(values[n][1], 'FATTURA SCADUTA --- Questa è una email automatica', ' Spettabile ' + values[n][0]+' '+ values[n][3]);
    var file = DriveApp.getFilesByName(values[n][4]); if (file.hasNext()) { MailApp.sendEmail(values[n][1],'FATTURA SCADUTA --- Questa è una email automatica',
    ' Spettabile ' + values[n][0] +' ' + values[n][3], { attachments: [file.next().getAs(MimeType.PDF)], name: values[n][4]})
    }else{
    MailApp.sendEmail("miamail.xxx", 'File non trovato', 'File non trovato ' + values[n][4]);}
    }
    }}

    Rispondi a questo commento
    • Friday, December 7, 2018 alle ore 01:18 Michele PisaniAutore

      Ciao Marco,
      difficile da dire senza verificare all'atto pratico quello succede. Potrebbe essere una questione di quota (ad esempio il corpo del messaggio che supera i 200Kb: https://developers.google.com/apps-script/guides/services/quotas) o del contenuto stesso del messaggio o di recupero degli allegati.

      Che motivazione ti viene data nella mail che ti avvisa della mancata consegna al destinatario?

      Ad ogni modo proverei ad effettuare un debug commentando alcune parti per escluderle dall'invio, ad esempio gli allegati, e verificare se la mail arriva in modo da capire se dipende da quelli o meno, ed in caso negativo togliere alcune parti dal corpo del messaggio e ripetere l'operazione.

      Se il problema dovesse persistere potrebbe essere d'aiuto segnalarlo nell'issue tracker: https://issuetracker.google.com/
      Ed iscriversi al gruppo su Facebook 'Fatti di Apps Script': https://www.facebook.com/groups/AppsScript/ dove ci sono altri sviluppatori e appassionati che possono essersi trovati nella tua stessa situazione.

      Fammi sapere se hai ulteriori informazioni o se sei riuscito a risolvere. Grazie,
      Michele

      Rispondi a questo commento
  4. Tuesday, November 19, 2019 alle ore 15:32 sandra

    è possibile modificare il formato della data che viene visualizzato nella mail. dovrei automatizzare l'invio di scadenze e con quel formato risulta poco leggibile.

    Rispondi a questo commento
  5. Friday, November 29, 2019 alle ore 14:19 Giacomo

    Buongiorno se volessi collegare a questo script anche il mandare mail al verificarsi di una condizione ?
    esempio manda una mail quando e2 < 2
    avete già un tutorial così?
    Grazie

    Rispondi a questo commento
    • Friday, November 29, 2019 alle ore 16:32 Michele PisaniAutore

      Ciao Giacomo,
      per ottenere quel risultato, sarà sufficiente verificare il contenuto della cella allo stesso modo del codice di esempio ma anziché un confronto tra date sarà un confronto tra numeri interi.
      Non c'è un tutorial specifico per quella condizione, il concetto è il medesimo, dovrà essere adattato il codice dell'esempio alla situazione.

      Rispondi a questo commento
  6. Sunday, March 8, 2020 alle ore 14:57 Denis

    Buongiorno è possibile inviare la mail (mittente) anzichè dall'account con il quale ci si è linkati dall'indirizzo di un particolare gruppo di google precedentemente creato? Grazie.

    Rispondi a questo commento
  7. Friday, June 26, 2020 alle ore 17:43 Simone

    Buongiorno,
    vorrei inserire il confronto della data nella cella con la stessa data ma di 2 mesi prima, che valore devo inserire al posto di "today > cell_date"?
    Grazie.

    Rispondi a questo commento
    • Friday, June 26, 2020 alle ore 20:10 Michele PisaniAutore

      Ciao Simone,
      su due piedi potrei dirti che il valore di 'today' potrebbe essere la data di 2 mesi fa (rispetto ad oggi) e quello di 'cell_date' la data di scadenza che si riferisce alla data effettiva del termine meno 2 mesi. In questo modo non serviranno altre variazioni al codice.

      Rispondi a questo commento
  8. Wednesday, April 14, 2021 alle ore 13:15 Buongiorno Michele,

    Buongiorno Michele, ho adattato lo script alle mie esigenze, ma essendo alle prime armi non riesco ad adattarlo bene alla mia richiesta che sarebbe quella di non inviare la mail ogni giorno partendo dall'inizio del mese in quanto la data è inferiore a quella odierna, ma vorrei inviarla soltanto il giorno prima della scadenza.
    Potresti aiutarmi Grazie

    Rispondi a questo commento
    • Thursday, April 15, 2021 alle ore 00:01 Michele PisaniAutore

      Ciao,
      potresti provare ad aggiungere le due righe che vedi sotto la variabile today per dichiarare e valorizzare una nuova variabile chiamata tomorrow, dopodiché nella condizione sostituire questa seconda variabile alla prima e applicare un operatore di uguaglianza:

        var today = new Date()

      var tomorrow = new Date(today)
      tomorrow.setDate(tomorrow.getDate() + 1)

      // ... altro codice presente
      var expired = tomorrow == cell_date;

      Rispondi a questo commento
      • Thursday, April 15, 2021 alle ore 11:23 Enrico

        Buongiorno Michele,
        Ho provato ad inserire il codice che mi hai consigliato ma non riesco a farlo funzionare.
        Se posto il codice mi restituisce continuamente un errore.

      • Thursday, April 15, 2021 alle ore 22:09 Michele PisaniAutore

        Ciao Enrico,
        cosa intendi con "non riesco a farlo funzionare"? Ricevi un errore particolare? Nel caso fammi sapere quale.

  9. Friday, April 16, 2021 alle ore 12:45 Enrico

    Buongiorno Michele,
    Non ho nessun errore restituito dal codice è soltanto che quando inserisco sul foglio la data presunta alla quale il giorno prima della scadenza non avviene nessun avvio della mail.
    Ti allego il codice Grazie Mille.



    function InviaNotificaScadenza() {
    var today = new Date();
    var tomorrow = new Date(today);
    tomorrow.setDate(tomorrow.getDate() +1);
    var values = SpreadsheetApp.getActiveSheet().getDataRange().getValues();
    var all_len = values.length ;
    var cell_date,expired;
    for(n=1;n<values.length;++n){
    var cell_date = values[n][2];
    //var expired = today > cell_date ;
    var expired = tomorrow == cell_date




    Rispondi a questo commento
  10. Friday, November 5, 2021 alle ore 09:04 Andrea

    Ciao Michele, sarebbe possibile far inviare una unica mail contenente diverse righe con indicate le informazioni delle scadenze? come si dovrebbe modificare il codice per farlo? grazie.

    Rispondi a questo commento
    • Friday, November 5, 2021 alle ore 22:33 Michele PisaniAutore

      Ciao Andrea,
      il contenuto della mail è rappresentato dal terzo parametro del metodo sendEmail. Ti basta inserire/concatenare le informazioni in quel punto, ad esempio per inserire la data di scadenza potresti scrivere una cosa del genere (basata sull'esempio del video dove la data di scadenza si trova in posizione values[n][2]):

      MailApp.sendEmail(values[n][1], 'Mail automatica', 'Servizio scaduto il ' + values[n][2] + ' per il sig. ' + values[n][0]);

      Rispondi a questo commento
  11. Wednesday, March 30, 2022 alle ore 18:50 Nicola

    Ciao Michele,

    grazie del video. Ho provato il codice (adattandolo alle mie esigenze) e quando lo eseguo manualmente invia le email ma esce messaggio di errore " Impossibile inviare l'email: nessun destinatario (riga 8, file "Email")". Nonostante questo errore invia le email correttamente.
    Quando invece lo deve fare tramite il trigger (ho impostato una volta al giorno) non parte nessuna email e nella sezione di gestione vedo stesso errore ("Impossibile inviare l'email: nessun destinatario at alertSender(Email:8:15)".
    Per caso sapresti aiutarmi?

    Metto di seguito il mio codice:

    function alertSender() {
    var today = new Date(); // es: 2018/03/30 (il formato effettivo della data sarà in 'full text string format')
    var values = SpreadsheetApp.getActiveSheet().getDataRange().getValues();
    for(n=1;n<values.length;++n){
    var cell_date = values[n][8];
    var expired = today > cell_date;
    if (expired) {
    MailApp.sendEmail(values[n][10], 'Alert sacchetti', 'Il negozio ' + values[n][0] + ' ha solo ' + values[n][7] + ' sacchetti rimanenti!' );

    }
    }
    }


    Grazie mille
    Nicola

    Rispondi a questo commento
    • Sunday, April 3, 2022 alle ore 12:20 Michele PisaniAutore

      Ciao Nicola,
      ad occhio sembrerebbe che nella posizione 10 dell'array non venga trovato un indirizzo email valido. Farei un controllo con Logger.log() per visualizzare il valore che l'array contiene.

      Rispondi a questo commento
  12. Wednesday, July 13, 2022 alle ore 18:58 Giuseppe

    Buingiorno Sig. Pisani,
    sto combattendo da due giorni con il suo report su come attivare email automatiche sullo scadenzario realizzato in ambiente excel di google.
    Premetto ho iniziato da qualche mese a lavorare con excel di google, e sinceramente grazie ai tutorial ho raggiunto grandi traguardi (per me ovviamente).
    Adesso ho uno scoglio che si riferisce alla programmazione di questo scadenzario, ni ritorna questo errore

    non riesco a caricare l'immagine, come posso fare

    Rispondi a questo commento
  13. Tuesday, March 26, 2024 alle ore 14:10 Antonio

    Salve Signor Michele volevo modificare il suo script per inviare una mail nella data di compleanno,
    ma non sto riuscendo.
    Ho fatto questa modifica
    var expired = today == cell_date;
    ma non riesco ad avere l'effetto desiderato

    Rispondi a questo commento
    • Tuesday, March 26, 2024 alle ore 14:36 Michele PisaniAutore

      Ciao Antonio,
      verifica con un log cosa contengono quelle due variabili che stai confrontando. Il problema potrebbe essere lì.

      Rispondi a questo commento
      • Tuesday, March 26, 2024 alle ore 15:25 Antonio

        15:23:42 Informazioni Tue Mar 26 2024 15:23:41 GMT+0100 (Central European Standard Time)Tue Mar 26 2024 00:00:00 GMT+0100 (Central European Standard Time)false
        15:23:42 Informazioni Tue Mar 26 2024 15:23:41 GMT+0100 (Central European Standard Time)Sun

        Logger.log(today+cell_date + expired);
        Jan 16 1994 00:00:00 GMT+0100 (Central European Standard Time)false
        15:23:42 Informazioni Tue Mar 26 2024 15:23:41 GMT+0100 (Central European Standard Time)Wed Aug 23 1989 00:00:00 GMT+0200 (Central European Summer Time)false
        15:23:42 Informazioni Tue Mar 26 2024 15:23:41 GMT+0100 (Central European Standard Time)Sat Feb 26 1977 00:00:00 GMT+0100 (Central European Standard Time)false

  14. Thursday, April 11, 2024 alle ore 10:57 Marcello

    Ciao Michele innanzitutto grazie, ma sbaglio o quello che hai scritto tu in risposta è per inviare il valore di più colonne della stessa riga nella stessa mail ?, ma come ha scritto Andrea per mandare in un'unica mail più righe (esempio tutte le fatture che scadono a fine mese) come bisognerebbe procedere?
    P.S. farai il seguito del tuo libro?
    ciao
    Grazie
    Marcello

    Rispondi a questo commento
    • Friday, April 12, 2024 alle ore 14:37 Michele PisaniAutore

      Ciao Marcello,
      in tal caso è necessario costruire una stringa all'interno del ciclo che ad ogni loop aggiunga le informazioni successive e spostare l'invio dell'e-mail fuori dal ciclo.

      Rispondi a questo commento
  15. Tuesday, July 16, 2024 alle ore 16:12 Stefano

    Ciao,
    sei bravissimo e complimenti per i tuoi video,
    vorrei sapere come adattare questa espressione per far si che il mittente del messaggio non risulti la e-mail da cui il messaggio effettivamente parte ma possa comparire un mittente predefinito come ad esempio:
    Marco Rossi anzichè marcorossi@gmail.com .

    grazie anticipatamente

    Rispondi a questo commento
    • Tuesday, July 16, 2024 alle ore 16:27 Michele PisaniAutore

      Ciao Stefano, grazie del feedback :) Per ottenere quello che stai cercando di fare potresti provare ad aggiungere (manualmente) un alias all'account da cui desideri inviare la posta ed utilizzare il servizio GmailApp.sendEmail, ad esempio:

      GmailApp.sendEmail('recipient@yourdomain.con', 'subject', 'body', {from: myAliases[0], name:'Name of the Alias'});

      Non ho provato sinceramente, per cui non so se Google è ancora flessibile da permettere questo passaggio.

      Rispondi a questo commento

Scrivi un commento

Il tuo indirizzo email non sarà pubblicato.I campi contrassegnati da un * sono obbligatori
Puoi utilizzare i seguenti tag nei commenti:
[bold]testo[/bold] se vuoi evidenziare un testo con il grassetto[code]function helloworld() { }[/code] se vuoi pubblicare una porzione di codice[url]https://www.appsscript.it[/url] se devi riferirti ad un indirizzo web