Analyser et libeller des messages Gmail avec Gemini et Vertex AI

Cette solution utilise Vertex AI et Gemini pour analyser les messages Gmail et les étiqueter en fonction de leur sentiment.

Niveau de programmation : intermédiaire
Durée : 30 minutes
Type de projet : module complémentaire Google Workspace

  • Module complémentaire Google Workspace qui étend Gmail dans une barre latérale.
    Figure 1 : Le module complémentaire Analyse du sentiment affiche une barre latérale dans Gmail, où les utilisateurs peuvent demander à Gemini d'analyser et d'appliquer des libellés aux messages en fonction du sentiment.
  • Message Gmail avec un sentiment neutre.
    Figure 2 : Le module complémentaire attribue le libellé TON NEUTRE 😐 à un message Gmail.
  • Un message Gmail avec un sentiment positif.
    Figure 3 : Le module complémentaire attribue le libellé TON JOYEUX 😊 à un e-mail Gmail.
  • Message Gmail exprimant un sentiment de contrariété.
    Figure 4 : Le module complémentaire attribue le libellé TON CONTRARIÉ 😡 à un message Gmail.

Objectifs

  • Comprendre ce que fait la solution
  • Comprendre le rôle des services Google dans la solution
  • Configurez l'environnement.
  • Configurez le projet Google Apps Script.
  • Exécutez le script.

À propos de cette solution

Capture d'écran du module complémentaire Google Workspace "Sentiment Analysis"

Cette solution est un module complémentaire Google Workspace qui applique des libellés en fonction du sentiment des messages Gmail. Pour analyser le contenu du message, le module complémentaire utilise Vertex AI pour inviter le modèle Gemini 2.5 Flash et renvoyer l'un des sentiments suivants :

  • Positif
  • Négatif
  • Neutre

Avec la réponse de Gemini, le module complémentaire applique un libellé Gmail correspondant au message.

Pour limiter la requête à l'API Vertex AI, ce module complémentaire n'analyse et n'applique des libellés qu'aux 10 messages les plus récents de la boîte de réception de l'utilisateur Gmail. Pour en savoir plus sur les quotas et les limites, consultez la documentation Vertex AI.

Fonctionnement

Cette solution est conçue dans Google Apps Script et utilise les services et produits Google suivants :

  • API Vertex AI : invite le modèle Gemini 2.5 Flash à analyser le contenu des e-mails Gmail et à identifier le sentiment.
  • Services Apps Script :

    • Service Gmail : récupère les libellés et les applique aux messages Gmail. Crée éventuellement des exemples de messages pour tester le module complémentaire.
    • Service de fiche : crée l'interface utilisateur du module complémentaire qui s'affiche sous forme de barre latérale dans Gmail.
    • Service UrlFetch : se connecte à l'API Vertex AI pour l'analyse des sentiments.
    • Service de script : pour appeler l'API Vertex AI, obtient un jeton d'accès OAuth 2.0 pour le module complémentaire à l'aide de la méthode getOAuthToken.

Prérequis

Configurer votre environnement

Cette section explique comment configurer votre environnement dans la console Google Cloud et Apps Script.

Configurer votre projet Cloud dans la console Google Cloud

Cette section vous explique comment activer l'API Vertex AI et configurer l'écran d'autorisation OAuth dans votre projet Cloud.

Activer l'API Vertex AI

  1. Dans la console Google Cloud, ouvrez votre projet Google Cloud et activez l'API Vertex AI :

    Activer l'API

  2. Vérifiez que vous activez l'API dans le bon projet Cloud, puis cliquez sur Suivant.

  3. Vérifiez que vous activez la bonne API, puis cliquez sur Activer.

Configurer l'écran d'autorisation OAuth

Les modules complémentaires Google Workspace nécessitent une configuration de l'écran de consentement. La configuration de l'écran de consentement OAuth de votre module complémentaire définit ce que Google affiche aux utilisateurs.

  1. Dans la console Google Cloud, accédez à Menu  > > Branding.

    Accéder à "Branding"

  2. Si vous avez déjà configuré , vous pouvez configurer les paramètres de l'écran d'autorisation OAuth suivants dans Branding, Audience et Accès aux données. Si le message pas encore configuré s'affiche, cliquez sur Commencer :
    1. Sous Informations sur l'application, dans Nom de l'application, saisissez le nom de l'application.
    2. Dans Adresse e-mail d'assistance utilisateur, sélectionnez une adresse e-mail d'assistance que les utilisateurs pourront contacter s'ils ont des questions sur leur consentement.
    3. Cliquez sur Suivant.
    4. Sous Audience, sélectionnez Interne.
    5. Cliquez sur Suivant.
    6. Sous Coordonnées, saisissez une adresse e-mail à laquelle vous pourrez être informé de toute modification apportée à votre projet.
    7. Cliquez sur Suivant.
    8. Sous Terminer, consultez le Règlement sur les données utilisateur dans les services d'API Google et, si vous l'acceptez, sélectionnez J'accepte le Règlement sur les données utilisateur dans les services d'API Google.
    9. Cliquez sur Continuer.
    10. Cliquez sur Créer.
  3. Pour l'instant, vous pouvez ignorer l'ajout de portées. À l'avenir, lorsque vous créerez une application à utiliser en dehors de votre organisation Google Workspace, vous devrez définir le type d'utilisateur sur Externe. Ajoutez ensuite les niveaux d'autorisation dont votre application a besoin. Pour en savoir plus, consultez le guide complet Configurer le consentement OAuth.

Créer et configurer votre projet Apps Script

Pour créer et configurer votre projet Apps Script pour le module complémentaire, procédez comme suit :

  1. Cliquez sur le bouton suivant pour ouvrir le projet Apps Script Analyse du sentiment dans Gmail avec Gemini et Vertex AI.
    Ouvrir le projet Apps Script

  2. Cliquez sur Vue d'ensemble .

  3. Sur la page "Présentation", cliquez sur Créer une copie Icône permettant de créer une copie.

  4. Obtenez le numéro de votre projet Cloud :

    1. Dans la console Google Cloud, accédez à Menu  > IAM et administration > Paramètres.

      Accéder à la page Paramètres de la section IAM et administration

    2. Dans le champ Numéro du projet, copiez la valeur.
  5. Associez votre projet Cloud à votre projet Apps Script :

    1. Dans le projet Apps Script que vous avez copié, cliquez sur Paramètres du projet Icône des paramètres du projet.
    2. Sous Projet Google Cloud Platform (GCP), cliquez sur Changer de projet.
    3. Dans Numéro de projet GCP, collez le numéro du projet Cloud.
    4. Cliquez sur Définir un projet.

Tester le module complémentaire

Pour essayer le module complémentaire, installez un déploiement de test, puis ouvrez le module complémentaire dans Gmail :

  1. Créez et installez un déploiement de test Apps Script :
    1. Dans le projet Apps Script que vous avez copié, cliquez sur Éditeur .
    2. Ouvrez le fichier Code.gs et cliquez sur Exécuter. Lorsque vous y êtes invité, autorisez le script.
    3. Cliquez sur Déployer > Tester les déploiements.
    4. Cliquez sur Installer > OK.
  2. Ouvrez Gmail.

    Accéder à Gmail

  3. Dans la barre latérale de droite, ouvrez le module complémentaire Analyse des sentiments.

  4. Si vous y êtes invité, autorisez le module complémentaire.

  5. Facultatif : Pour créer des messages à tester avec votre module complémentaire, cliquez sur Générer des exemples d'e-mails. Trois messages s'affichent dans votre boîte de réception. Si vous ne les voyez pas, actualisez la page.

  6. Pour ajouter des libellés, cliquez sur Analyser les e-mails.

Le module complémentaire examine les 10 derniers messages de votre boîte de réception, puis applique l'un des libellés suivants en fonction du contenu du message :

  • TON JOYEUX 😊
  • TON NEUTRE 😐
  • TON CONTRARIÉ 😡

Examiner le code

Examinez le code Apps Script de cette solution :

Afficher le code source

Code.gs

gmail-sentiment-analysis/Code.gs
/*
Copyright 2024 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/**
 * Triggered when the add-on is opened from the Gmail homepage.
 *
 * @param {Object} e - The event object.
 * @returns {Card} - The homepage card.
 */
function onHomepageTrigger(e) {
  return buildHomepageCard();
}

Cards.gs

gmail-sentiment-analysis/Cards.gs
/*
Copyright 2024-2025 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/**
 * Builds the main card displayed on the Gmail homepage.
 *
 * @returns {Card} - The homepage card.
 */
function buildHomepageCard() {
  // Create a new card builder
  const cardBuilder = CardService.newCardBuilder();

  // Create a card header
  const cardHeader = CardService.newCardHeader();
  cardHeader.setImageUrl('https://fonts.gstatic.com/s/i/googlematerialicons/mail/v6/black-24dp/1x/gm_mail_black_24dp.png');
  cardHeader.setImageStyle(CardService.ImageStyle.CIRCLE);
  cardHeader.setTitle("Analyze your Gmail");

  // Add the header to the card
  cardBuilder.setHeader(cardHeader);

  // Create a card section
  const cardSection = CardService.newCardSection();

  // Create buttons for generating sample emails and analyzing sentiment
  const buttonSet = CardService.newButtonSet();

  // Create "Generate sample emails" button
  const generateButton = createFilledButton('Generate sample emails', 'generateSampleEmails', '#34A853');
  buttonSet.addButton(generateButton);

  // Create "Analyze emails" button
  const analyzeButton = createFilledButton('Analyze emails', 'analyzeSentiment', '#FF0000');
  buttonSet.addButton(analyzeButton);

  // Add the button set to the section
  cardSection.addWidget(buttonSet);

  // Add the section to the card
  cardBuilder.addSection(cardSection);

  // Build and return the card
  return cardBuilder.build();
}

/**
 * Creates a filled text button with the specified text, function, and color.
 *
 * @param {string} text - The text to display on the button.
 * @param {string} functionName - The name of the function to call when the button is clicked.
 * @param {string} color - The background color of the button.
 * @returns {TextButton} - The created text button.
 */
function createFilledButton(text, functionName, color) {
  // Create a new text button
  const textButton = CardService.newTextButton();

  // Set the button text
  textButton.setText(text);

  // Set the action to perform when the button is clicked
  const action = CardService.newAction();
  action.setFunctionName(functionName);
  textButton.setOnClickAction(action);

  // Set the button style to filled
  textButton.setTextButtonStyle(CardService.TextButtonStyle.FILLED);

  // Set the background color
  textButton.setBackgroundColor(color);

  return textButton;
}

/**
 * Creates a notification response with the specified text.
 *
 * @param {string} notificationText - The text to display in the notification.
 * @returns {ActionResponse} - The created action response.
 */
function buildNotificationResponse(notificationText) {
  // Create a new notification
  const notification = CardService.newNotification();
  notification.setText(notificationText);

  // Create a new action response builder
  const actionResponseBuilder = CardService.newActionResponseBuilder();

  // Set the notification for the action response
  actionResponseBuilder.setNotification(notification);

  // Build and return the action response
  return actionResponseBuilder.build();
}

Gmail.gs

gmail-sentiment-analysis/Gmail.gs
/*
Copyright 2024-2025 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/**
 * Analyzes the sentiment of the first 10 threads in the inbox
 * and labels them accordingly.
 *
 * @returns {ActionResponse} - A notification confirming completion.
 */
function analyzeSentiment() {
  // Analyze and label emails
  analyzeAndLabelEmailSentiment();

  // Return a notification
  return buildNotificationResponse("Successfully completed sentiment analysis");
}

/**
 * Analyzes the sentiment of emails and applies appropriate labels.
 */
function analyzeAndLabelEmailSentiment() {
  // Define label names
  const labelNames = ["HAPPY TONE 😊", "NEUTRAL TONE 😐", "UPSET TONE 😡"];

  // Get or create labels for each sentiment
  const positiveLabel = GmailApp.getUserLabelByName(labelNames[0]) || GmailApp.createLabel(labelNames[0]);
  const neutralLabel = GmailApp.getUserLabelByName(labelNames[1]) || GmailApp.createLabel(labelNames[1]);
  const negativeLabel = GmailApp.getUserLabelByName(labelNames[2]) || GmailApp.createLabel(labelNames[2]);

  // Get the first 10 threads in the inbox
  const threads = GmailApp.getInboxThreads(0, 10);

  // Iterate through each thread
  for (const thread of threads) {
    // Iterate through each message in the thread
    const messages = thread.getMessages();
    for (const message of messages) {
      // Get the plain text body of the message
      const emailBody = message.getPlainBody();

      // Analyze the sentiment of the email body
      const sentiment = processSentiment(emailBody);

      // Apply the appropriate label based on the sentiment
      if (sentiment === 'positive') {
        thread.addLabel(positiveLabel);
      } else if (sentiment === 'neutral') {
        thread.addLabel(neutralLabel);
      } else if (sentiment === 'negative') {
        thread.addLabel(negativeLabel);
      }
    }
  }
}

/**
 * Generates sample emails for testing the sentiment analysis.
 *
 * @returns {ActionResponse} - A notification confirming email generation.
 */
function generateSampleEmails() {
  // Get the current user's email address
  const userEmail = Session.getActiveUser().getEmail();

  // Define sample emails
  const sampleEmails = [
    {
      subject: 'Thank you for amazing service!',
      body: 'Hi, I really enjoyed working with you. Thank you again!',
      name: 'Customer A'
    },
    {
      subject: 'Request for information',
      body: 'Hello, I need more information on your recent product launch. Thank you.',
      name: 'Customer B'
    },
    {
      subject: 'Complaint!',
      body: '',
      htmlBody: `<p>Hello, You are late in delivery, again.</p>
<p>Please contact me ASAP before I cancel our subscription.</p>`,
      name: 'Customer C'
    }
  ];

  // Send each sample email
  for (const email of sampleEmails) {
    GmailApp.sendEmail(userEmail, email.subject, email.body, {
      name: email.name,
      htmlBody: email.htmlBody
    });
  }

  // Return a notification
  return buildNotificationResponse("Successfully generated sample emails");
}

Vertex.gs

gmail-sentiment-analysis/Vertex.gs
/*
Copyright 2024-2025 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Replace with your project ID
const PROJECT_ID = '[ADD YOUR GCP PROJECT ID HERE]';

// Location for your Vertex AI model
const VERTEX_AI_LOCATION = 'us-central1';

// Model ID to use for sentiment analysis
const MODEL_ID = 'gemini-2.5-flash';

/**
 * Sends the email text to Vertex AI for sentiment analysis.
 *
 * @param {string} emailText - The text of the email to analyze.
 * @returns {string} - The sentiment of the email ('positive', 'negative', or 'neutral').
 */
function processSentiment(emailText) {
  // Construct the API endpoint URL
  const apiUrl = `https://${VERTEX_AI_LOCATION}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${VERTEX_AI_LOCATION}/publishers/google/models/${MODEL_ID}:generateContent`;

  // Prepare the request payload
  const payload = {
    contents: [
      {
        role: "user",
        parts: [
          {
            text: `Analyze the sentiment of the following message: ${emailText}`
          }
        ]
      }
    ],
    generationConfig: {
      temperature: 0.9,
      maxOutputTokens: 1024,
      responseMimeType: "application/json",
      // Expected response format for simpler parsing.
      responseSchema: {
        type: "object",
        properties: {
          response: {
            type: "string",
            enum: ["positive", "negative", "neutral"]
          }
        }
      }
    }
  };

  // Prepare the request options
  const options = {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${ScriptApp.getOAuthToken()}`
    },
    contentType: 'application/json',
    muteHttpExceptions: true, // Set to true to inspect the error response
    payload: JSON.stringify(payload)
  };

  // Make the API request
  const response = UrlFetchApp.fetch(apiUrl, options);

  // Parse the response. There are two levels of JSON responses to parse.
  const parsedResponse = JSON.parse(response.getContentText());
  const sentimentResponse = JSON.parse(parsedResponse.candidates[0].content.parts[0].text).response;

  // Return the sentiment
  return sentimentResponse;
}

appsscript.json

gmail-sentiment-analysis/appsscript.json
{
  "timeZone": "America/Toronto",
  "oauthScopes": [
    "https://www.googleapis.com/auth/cloud-platform",
    "https://www.googleapis.com/auth/gmail.addons.execute",
    "https://www.googleapis.com/auth/gmail.labels",
    "https://www.googleapis.com/auth/gmail.modify",
    "https://www.googleapis.com/auth/script.external_request",
    "https://www.googleapis.com/auth/userinfo.email"
  ],
  "addOns": {
    "common": {
      "name": "Sentiment Analysis",
      "logoUrl": "https://fonts.gstatic.com/s/i/googlematerialicons/sentiment_extremely_dissatisfied/v6/black-24dp/1x/gm_sentiment_extremely_dissatisfied_black_24dp.png"
    },
    "gmail": {
      "homepageTrigger": {
        "runFunction": "onHomepageTrigger",
        "enabled": true
      }
    }
  },
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8"
}

Effectuer un nettoyage

Pour éviter que les ressources utilisées dans ce tutoriel soient facturées sur votre compte Google Cloud, nous vous recommandons de supprimer le projet Cloud.

  1. Dans la console Google Cloud, accédez à la page Gérer les ressources. Cliquez sur Menu > IAM et administration > Gérer les ressources.

    Accéder au gestionnaire de ressources

  2. Dans la liste des projets, sélectionnez celui que vous souhaitez supprimer, puis cliquez sur Supprimer .
  3. Dans la boîte de dialogue, saisissez l'ID du projet, puis cliquez sur Arrêter pour supprimer le projet.

Étapes suivantes