Analisar e rotular mensagens do Gmail com o Gemini e a Vertex AI

Essa solução usa a Vertex AI e o Gemini para analisar mensagens do Gmail e rotulá-las com base no sentimento.

Nível de programação: intermediário
Duração: 30 minutos
Tipo de projeto: complemento do Google Workspace

  • Um complemento do Google Workspace que estende o Gmail em uma barra lateral.
    Figura 1:o complemento Análise de sentimentos mostra uma barra lateral no Gmail em que os usuários podem pedir ao Gemini para analisar e aplicar rótulos às mensagens com base no sentimento.
  • Uma mensagem do Gmail com sentimento neutro.
    Figura 2:o complemento marca uma mensagem do Gmail com o marcador TOM NEUTRO 😐.
  • Uma mensagem do Gmail com sentimento positivo.
    Figura 3:o complemento marca uma mensagem do Gmail com o marcador TOM FELIZ 😊.
  • Uma mensagem do Gmail com sentimento de raiva.
    Figura 4:o complemento marca uma mensagem do Gmail com o marcador TOM CHATEADO 😡.

Objetivos

  • Entenda o que a solução faz.
  • Entenda o que os Serviços do Google fazem na solução.
  • Configure o ambiente.
  • Configure o projeto do Google Apps Script.
  • Execute o script.

Sobre esta solução

Captura de tela do complemento de análise de sentimento do Google Workspace

Essa solução é um complemento do Google Workspace que aplica marcadores com base no sentimento das mensagens do Gmail. Para analisar o conteúdo da mensagem, o complemento usa a Vertex AI para solicitar o modelo Gemini 2.5 Flash e retornar um dos seguintes sentimentos:

  • Positivo
  • Negativa
  • Neutro

Com a resposta do Gemini, o complemento aplica um marcador correspondente do Gmail à mensagem.

Para limitar a solicitação à API Vertex AI, esse complemento analisa e aplica marcadores apenas às 10 mensagens mais recentes na caixa de entrada do usuário do Gmail. Para saber mais sobre cotas e limites, acesse a documentação da Vertex AI.

Como funciona

Essa solução foi criada no Google Apps Script e usa os seguintes serviços e produtos do Google:

  • API Vertex AI: solicita ao modelo Gemini 2.5 Flash que analise o conteúdo das mensagens do Gmail e identifique o sentimento.
  • Serviços do Apps Script:

    • Serviço do Gmail: recupera e aplica marcadores às mensagens do Gmail. Opcional: cria mensagens de exemplo para testar o complemento.
    • Serviço de card: cria a interface do usuário do complemento que aparece como uma barra lateral no Gmail.
    • Serviço de busca de URL: conecta-se à API Vertex AI para análise de sentimentos.
    • Serviço de script: para chamar a API Vertex AI, recebe um token de acesso do OAuth 2.0 para o complemento usando o método getOAuthToken.

Pré-requisitos

Configurar o ambiente

Nesta seção, explicamos como configurar seu ambiente no console do Google Cloud e no Apps Script.

Configurar seu projeto do Cloud no console do Google Cloud

Esta seção mostra como ativar a API Vertex AI e configurar a tela de consentimento do OAuth no seu projeto do Cloud.

Ativar a API Vertex AI

  1. No console do Google Cloud, abra seu projeto do Google Cloud e ative a API Vertex AI:

    Ativar a API

  2. Confirme se você está ativando a API no projeto do Cloud correto e clique em Próxima.

  3. Confirme se você está ativando a API correta e clique em Ativar.

Configurar a tela de permissão OAuth

Os complementos do Google Workspace exigem uma configuração de tela de consentimento. Configurar a tela de permissão OAuth do seu complemento define o que o Google mostra aos usuários.

  1. No console do Google Cloud, acesse Menu > > Branding.

    Acessar Branding

  2. Se você já tiver configurado o , poderá definir as seguintes configurações da tela de permissão do OAuth em Branding, Público-alvo e Acesso a dados. Se aparecer uma mensagem informando que ainda não foi configurado, clique em Começar:
    1. Em Informações do app, no campo Nome do app, insira um nome para o app.
    2. Em E-mail para suporte do usuário, escolha um endereço de e-mail para que os usuários entrem em contato com você se tiverem dúvidas sobre o consentimento deles.
    3. Clique em Próxima.
    4. Em Público-alvo, selecione Interno.
    5. Clique em Próxima.
    6. Em Informações de contato, insira um Endereço de e-mail para receber notificações sobre mudanças no seu projeto.
    7. Clique em Próxima.
    8. Em Concluir, leia a Política de dados do usuário dos serviços de API do Google e, se concordar, selecione Concordo com a Política de dados do usuário dos serviços de API do Google.
    9. Clique em Continuar.
    10. Clique em Criar.
  3. Por enquanto, você pode pular a adição de escopos. No futuro, quando você criar um app para uso fora da sua organização do Google Workspace, mude o Tipo de usuário para Externo. Em seguida, adicione os escopos de autorização necessários para o app. Para saber mais, consulte o guia completo Configurar a permissão OAuth.

Criar e configurar seu projeto do Apps Script

Para criar e configurar seu projeto do Apps Script para o complemento, siga estas etapas:

  1. Clique no botão a seguir para abrir o projeto do Apps Script Análise de sentimentos do Gmail com o Gemini e a Vertex AI.
    Abra o projeto do Apps Script

  2. Clique em Visão geral .

  3. Na página de visão geral, clique em Fazer uma cópia O ícone para fazer uma cópia.

  4. Confira o número do seu projeto do Cloud:

    1. No console do Google Cloud, acesse Menu > IAM e administrador > Configurações.

      Acessar as configurações do IAM e do administrador

    2. No campo Número do projeto, copie o valor.
  5. Conecte seu projeto do Cloud ao projeto do Apps Script:

    1. No projeto copiado do Apps Script, clique em Configurações do projeto O ícone das configurações do projeto.
    2. Em Projeto do Google Cloud Platform (GCP), clique em Mudar projeto.
    3. Em Número do projeto do GCP, cole o número do projeto do Cloud.
    4. Clique em Configurar projeto.

Testar o complemento

Para testar o complemento, instale uma implantação de teste e abra o complemento no Gmail:

  1. Crie e instale uma implantação de teste do Apps Script:
    1. No projeto copiado do Apps Script, clique em Editor .
    2. Abra o arquivo Code.gs e clique em Executar. Quando solicitado, autorize o script.
    3. Clique em Implantar > Testar implantações.
    4. Clique em Instalar > Concluído.
  2. Abra o Gmail.

    Acesse o Gmail.

  3. Na barra lateral à direita, abra o complemento Análise de sentimentos.

  4. Se solicitado, autorize o complemento.

  5. Opcional: para criar mensagens de teste com seu complemento, clique em Gerar e-mails de amostra. Três mensagens aparecem na sua caixa de entrada. Se eles não aparecerem, atualize a página.

  6. Para adicionar rótulos, clique em Analisar e-mails.

O complemento analisa as 10 mensagens mais recentes na sua caixa de entrada e aplica um dos seguintes rótulos com base no conteúdo da mensagem:

  • TOM ALEGRE 😊
  • TOM NEUTRO 😐
  • TOM DE RAIVA 😡

Revisar o código

Analise o código do Apps Script para esta solução:

Acessar o código-fonte

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"
}

Limpar

Para evitar cobranças na sua conta do Google Cloud pelos recursos usados neste tutorial, recomendamos que você exclua o projeto do Cloud.

  1. No console do Google Cloud, acesse a página Gerenciar recursos. Clique em Menu > IAM e administrador > Gerenciar recursos.

    Acesse o Resource Manager

  2. Na lista de projetos, selecione o projeto que você quer excluir e clique em Excluir .
  3. Na caixa de diálogo, digite o ID do projeto e clique em Encerrar para excluí-lo.

Próximas etapas