+180 XP

Automatiser avec Apps Script et Workspace

Google Apps Script combiné à l'API Gemini peut transformer Workspace : d'un endroit où vous travaillez, il devient un endroit qui travaille pour vous. Labelliser automatiquement les emails entrants selon l'intention, rédiger des réponses, ou compiler un rapport hebdomadaire dans un Sheet depuis des lignes brutes sans que vous y touchiez. Ce qui débloque tout, c'est qu'Apps Script vit déjà à l'intérieur de Gmail, Sheets, Drive et Calendar, avec un accès authentifié à vos données, et que Gemini lui apporte le jugement. Vous branchez les deux avec un seul appel HTTP.

Cette leçon montre le câblage, un exemple concret qui fonctionne, et les garde-fous qui comptent dès lors que le script tourne sans surveillance sur un trigger.

Pourquoi Apps Script est la bonne colle

Apps Script est le runtime JavaScript serverless de Google intégré à Workspace. Vous ne provisionnez rien. Un script peut lire vos threads Gmail (GmailApp), écrire dans une feuille de calcul (SpreadsheetApp), et s'exécuter sur un trigger temporel, le tout avec les permissions de votre compte.

Ce qu'il n'a pas nativement, c'est le raisonnement. C'est la partie Gemini. Vous appelez l'API Gemini depuis le script avec `UrlFetchApp`, vous lui envoyez du texte, et vous récupérez une sortie structurée.

Deux façons d'authentifier l'appel :

  • Clé API depuis [Google AI Studio](https://aistudio.google.com) : le plus rapide pour démarrer. Bien pour les automatisations personnelles et les prototypes.
  • Vertex AI avec un service account : le bon choix quand l'automatisation appartient à une organisation, nécessite des contrôles IAM, une résidence des données ou des périmètres VPC. Voir cloud.google.com/vertex-ai.

Pour un rapport hebdomadaire personnel, la voie clé API convient. Nous l'utiliserons et signalerons où vous basculeriez.

L'exemple : un rapport hebdomadaire des emails support

L'objectif : chaque lundi à 7h, scanner les emails de la semaine passée labellisés `support`, faire classer chacun par Gemini selon la catégorie et l'urgence, et ajouter une ligne de synthèse propre à un Sheet de suivi.

L'astuce qui rend cela fiable, c'est la sortie structurée : vous demandez à Gemini de renvoyer du JSON conforme à un schéma plutôt que de la prose. L'API Gemini prend en charge un responseSchema, ce qui contraint le modèle à produire du JSON valide. Cela supprime l'étape fragile du « parser le paragraphe du modèle ».

L'appel de classification

Voici le cœur : une fonction qui envoie un batch de sujets et d'extraits d'emails et récupère des classifications typées.

javascript
const GEMINI_KEY = PropertiesService.getScriptProperties().getProperty('GEMINI_KEY');
const MODEL = 'gemini-2.5-flash';

function classifyEmails(emails) {
  const url = `https://generativelanguage.googleapis.com/v1beta/models/${MODEL}:generateContent?key=${GEMINI_KEY}`;
  const prompt = 'Classify each support email. Categories: billing, bug, feature_request, other. ' +
    'Urgency: low, medium, high.\n\n' +
    emails.map((e, i) => `[${i}] Subject: ${e.subject}\nSnippet: ${e.snippet}`).join('\n\n');

  const payload = {
    contents: [{ parts: [{ text: prompt }] }],
    generationConfig: {
      responseMimeType: 'application/json',
      responseSchema: {
        type: 'array',
        items: {
          type: 'object',
          properties: {
            index: { type: 'integer' },
            category: { type: 'string', enum: ['billing', 'bug', 'feature_request', 'other'] },
            urgency: { type: 'string', enum: ['low', 'medium', 'high'] }
          },
          required: ['index', 'category', 'urgency']
        }
      }
    }
  };

  const res = UrlFetchApp.fetch(url, {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify(payload),
    muteHttpExceptions: true
  });

  if (res.getResponseCode() !== 200) {
    throw new Error(`Gemini API ${res.getResponseCode()}: ${res.getContentText()}`);
  }
  const body = JSON.parse(res.getContentText());
  return JSON.parse(body.candidates[0].content.parts[0].text);
}

Ce dont un ingénieur senior se soucierait :

  • La clé vit dans les Script Properties, jamais dans le code source. Définissez-la une fois dans Project Settings, ou avec PropertiesService.getScriptProperties().setProperty('GEMINI_KEY', '...').
  • gemini-2.5-flash est le bon niveau ici. Flash est rapide et peu coûteux, et la classification est exactement son terrain de jeu. Réservez Pro aux tâches exigeant un raisonnement plus profond (synthèse longue, jugement multi-étapes difficile). Vérifiez les noms de modèles actuels sur ai.google.dev avant de déployer, car les niveaux évoluent.
  • muteHttpExceptions: true vous permet de lire le corps de l'erreur au lieu d'obtenir une exception générique. Vous voudrez ce texte dans vos logs.
  • Regroupez les emails dans un seul appel. Envoyer une requête par email consomme du quota et du temps. Un seul prompt avec tous les extraits de la semaine coûte bien moins cher, et le schéma garde les résultats alignés par index.

Le brancher à Gmail et Sheets

L'orchestration autour de l'appel, c'est de l'Apps Script ordinaire :

javascript
function weeklyReport() {
  const since = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
  const query = `label:support after:${Utilities.formatDate(since, 'GMT', 'yyyy/MM/dd')}`;
  const threads = GmailApp.search(query, 0, 50);

  const emails = threads.map(t => {
    const msg = t.getMessages()[0];
    return { subject: msg.getSubject(), snippet: msg.getPlainBody().slice(0, 400) };
  });
  if (emails.length === 0) return;

  const results = classifyEmails(emails);

  const sheet = SpreadsheetApp.openById('YOUR_SHEET_ID').getSheetByName('Weekly');
  const counts = { billing: 0, bug: 0, feature_request: 0, other: 0, high: 0 };
  results.forEach(r => {
    counts[r.category]++;
    if (r.urgency === 'high') counts.high++;
  });
  sheet.appendRow([new Date(), emails.length, counts.billing, counts.bug,
    counts.feature_request, counts.other, counts.high]);
}

Ensuite, créez un trigger pour qu'il tourne sans surveillance : dans l'éditeur, cliquez sur l'icône horloge (Triggers), ou faites-le une fois en code :

javascript
function installTrigger() {
  ScriptApp.newTrigger('weeklyReport')
    .timeBased().onWeekDay(ScriptApp.WeekDay.MONDAY).atHour(7).create();
}

Exécutez installTrigger une fois. À partir de là, `weeklyReport` se déclenche chaque lundi matin sans aucun humain dans la boucle. C'est tout l'intérêt, et c'est aussi précisément là que le risque commence.

Garde-fous pour les exécutions sans surveillance

Un script qui tourne pendant que vous dormez, qui détient votre scope Gmail et qui appelle un modèle externe exige de la discipline. Les modes de défaillance sont différents du prompting interactif parce que personne ne regarde la sortie.

1. Limitez le rayon d'action

Cet exemple lit seulement Gmail et ajoute des lignes à un Sheet. Il ne supprime jamais, n'envoie jamais, ne modifie jamais de thread. Gardez vos automatisations en lecture-et-ajout par défaut. Dès qu'un script peut envoyer des emails ou supprimer des fichiers sans surveillance, une mauvaise sortie du modèle ou un bug devient une action irréversible.

Si vous passez ensuite aux réponses automatiques ou au labelling automatique qui déplace du courrier, ajoutez un mode dry-run : écrivez l'action proposée dans un Sheet pendant une semaine et relisez-la avant de laisser le script agir pour de vrai.

2. Ne demandez que les scopes dont vous avez besoin

Apps Script déduit les scopes OAuth des API que vous appelez, mais vous devriez les épingler explicitement dans le manifeste, pour qu'une nouvelle fonction égarée ne puisse pas élargir l'accès silencieusement. Dans appsscript.json :

json
{
  "oauthScopes": [
    "https://www.googleapis.com/auth/gmail.readonly",
    "https://www.googleapis.com/auth/spreadsheets",
    "https://www.googleapis.com/auth/script.external_request"
  ]
}

gmail.readonly signifie que même une version buguée ne peut littéralement pas envoyer ni supprimer. Cette seule ligne est votre garde-fou le plus solide.

3. Ne faites jamais confiance à la sortie du modèle comme flux de contrôle

Le modèle renvoie des catégories. Validez-les contre votre enum avant de les utiliser comme clés d'objet, exactement comme le schéma l'impose. Si une valeur inattendue arrive, loguez-la et passez, plutôt que de faire planter toute l'exécution ou d'écrire n'importe quoi. La sortie structurée rend cela rare, mais la défense en profondeur ne coûte pas cher.

4. Gérez le quota, la latence et les échecs partiels

Les appels UrlFetchApp échouent parfois. Apps Script a aussi des limites de temps d'exécution par run. Enveloppez l'appel API dans un retry avec backoff pour les erreurs transitoires, et concevez le job de sorte qu'un échec du lundi ne perde pas silencieusement les données du lundi :

javascript
function fetchWithRetry(url, options, tries = 3) {
  for (let i = 0; i < tries; i++) {
    const res = UrlFetchApp.fetch(url, options);
    if (res.getResponseCode() < 500) return res;
    Utilities.sleep(1000 * Math.pow(2, i));
  }
  throw new Error('Gemini API failed after retries');
}

5. Surveillez le coût et la confidentialité

Flash est peu coûteux, mais une boucle incontrôlée ou un trigger mal configuré pour tourner toutes les heures, ça chiffre. Mettez une alerte de facturation sur le projet. Côté confidentialité : vous envoyez du contenu d'emails à une API. Pour un usage personnel, la clé AI Studio est acceptable, mais pour tout ce qui touche à des données clients ou collaborateurs, passez à Vertex AI, où vous obtenez un traitement des données de niveau entreprise, IAM, et la possibilité de garder les données dans une région. Ce n'est pas un confort pour des déploiements organisationnels ; c'est la frontière entre un prototype et quelque chose que la conformité approuvera.

Build a Gmail automation with Apps Script and Gemini

Watch on YouTube

Vérification des acquis

1. Selon la leçon, qu'apporte fondamentalement la combinaison d'Apps Script et de l'API Gemini, qu'aucun des deux ne possède pleinement seul ?

2. Pourquoi la leçon recommande-t-elle d'utiliser la sortie structurée (un responseSchema) lors de l'appel à Gemini depuis le script ?

3. Dans quel scénario préféreriez-vous Vertex AI avec un service account plutôt qu'une clé API Google AI Studio ?

CHOIX MULTIPLES

4. Sélectionnez TOUTES les affirmations qui décrivent correctement pourquoi Apps Script est décrit comme « la bonne colle » pour ce type d'automatisation.

Sélectionnez toutes les réponses correctes.

CHOIX MULTIPLES

5. Sélectionnez TOUTES les tâches que la leçon présente comme des choses que cette automatisation Apps Script + Gemini peut faire pour vous.

Sélectionnez toutes les réponses correctes.

Quand aller au-delà d'Apps Script

Apps Script est parfait pour « ça vit dans Workspace et fait une tâche délimitée sur un planning ». C'est le mauvais outil dès que vous avez besoin d'un véritable comportement d'agent multi-étapes : des outils qui appellent d'autres outils, de la planification, de la mémoire entre les étapes, ou une orchestration que vous voulez tester et versionner comme du vrai logiciel.

À ce stade, l'écosystème Gemini vous offre des options mieux adaptées :

  • [Agent Development Kit (ADK)](https://google.github.io/adk-docs/) : un framework open-source pour construire des agents avec outils, planification et orchestration multi-agents, déployable sur votre propre infrastructure ou sur Vertex AI Agent Engine. À utiliser quand la logique déborde d'un seul script.
  • Gemini CLI et Gemini Code Assist : pour l'automatisation côté développeur dans votre terminal et votre IDE, pas pour les workflows documentaires Workspace.
  • Gems : pour des assistants réutilisables et instruction-tuned dans l'application Gemini, quand un humain est dans la boucle et que vous n'avez pas besoin de code du tout.

La règle de décision : si la tâche est « lire des données Workspace, poser à Gemini une question précise, écrire le résultat quelque part dans Workspace, sur un planning », Apps Script gagne par sa simplicité. Si la tâche implique un agent qui décide quelles actions entreprendre au fil de nombreuses étapes, passez à ADK sur Vertex AI.

Un pattern à voler : ancrer le rapport

Vous pouvez rendre la synthèse hebdomadaire plus intelligente en demandant à Gemini de rédiger un court récit des tendances, pas seulement des compteurs. Ajoutez un deuxième appel qui prend les compteurs de la semaine plus la ligne de la semaine précédente et demande une note « ce qui a changé » en deux phrases, ajoutée au Sheet. Gardez ce prompt étroitement délimité et toujours contraint par un schéma (un seul champ texte `summary`) pour qu'il reste prévisible dans une exécution sans surveillance. Peu de raisonnement, gros gain de lisibilité, et toujours peu coûteux sur Flash.

À retenir

  • Apps Script est la colle, Gemini est le jugement. Lisez les données Workspace avec les services natifs, appelez l'API Gemini avec UrlFetchApp, réécrivez les résultats, le tout sous votre propre authentification et un trigger temporel.
  • Utilisez la sortie structurée (`responseSchema`) et regroupez vos requêtes. Le JSON contraint élimine le parsing fragile, et un appel groupé par exécution bat un appel par élément en coût, en vitesse et en quota.
  • Faites de la lecture-et-ajout le défaut et épinglez des scopes OAuth minimaux. gmail.readonly dans appsscript.json est une garantie de sécurité plus forte que n'importe quel commentaire de code. Ajoutez une revue en dry-run avant qu'un script n'envoie, ne déplace ou ne supprime quoi que ce soit.
  • Concevez pour l'échec sans surveillance : retries avec backoff, validation contre vos enums, alertes de facturation, et erreurs loguées que vous pouvez réellement lire.
  • Changez d'outil délibérément. Restez sur Apps Script pour les tâches planifiées délimitées ; passez à ADK sur Vertex AI quand vous avez besoin d'une véritable orchestration d'agents ou de contrôles de données de niveau entreprise.