Nesse tutorial você vai aprender de forma prática como criar sistema que se autentica no OAuth do Google para ler e-mails usando o Gmail API.

A API do Gmail é muito útil para a criação de aplicativos para poder identificar e-mails indesejados e também oferecer serviços em forma de SaaS para limpar caixas de entradas.

Utilizaremos a seguinte stack nesse tutorial:

  • Frontend: Javascript (fetch + botão de login)
  • Backend: Nodejs usando o módulo Express
  • Biblioteca npm: googleapis
  • OAuth: Google Cloud Console (GCP)

Criar as credenciais necessárias para autenticar no OAuth

  • Vá em https://console.cloud.google.com
  • Crie um novo projeto
  • Acesse Google Auth Platform → Clientes → Criar cliente

    Preencha o formulário, informando o tipo de aplicativo como Aplicativo da Web, dê um nome ao seu novo aplicativo, e em URIs de redirecionamento autorizados, informe http://localhost:4000/oauth/receive, que vai ser utilizado em nosso exemplo.

    Clique em Criar e no próximo popup, anote o ID do cliente (Client ID) e a Chave secreta do cliente (Client Secret), vamos precisar dessas informações adiante.
  • Acesse Google Auth Platform → Branding e preencha o nome do app, e-mail para suporte do usuário e dados do contado do desenvolvedor para iniciarmos os testes.

Configurando o backend (Nodejs + Express)

Instalar dependências

Crie uma nova pasta para iniciar um novo projeto NodeJS.
Abra o terminal ou o prompt de comando e digite o código abaixo.

npm init -y
npm install express express-session googleapis body-parser

Estrutura de pastas do nosso projeto

project/
├─ server.mjs
├─ tokens.json
└─ public/
      └─ index.html
Arquivo server.mjs

Crie o arquivo server.mjs e altere a variável CLIENT_ID com o seu ID do cliente, e o CLIENT_SECRET com a Chave secreta do cliente

import express from "express";
import session from "express-session";
import fs from "fs";
import { google } from "googleapis";
import bodyParser from "body-parser";

const app = express();
const PORT = 4000;

const CLIENT_ID = "INSIRA_SEU_CLIENT_ID"; // Exemplo: 292545165314-jqgquadfjl5pjh53vbosj0k8djm91u6r.apps.googleusercontent.com
const CLIENT_SECRET = "INSIRA_SEU_CLIENT_SECRET"; // Exemplo: GOCSPX-2rmk...(omitido)
const REDIRECT_URI = "http://localhost:4000/oauth/receive";
const SCOPES = ["https://www.googleapis.com/auth/gmail.readonly"];

const oAuth2Client = new google.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI);

app.use(express.static("public"));
app.use(bodyParser.json());
app.use(
    session({
        secret: "informar-string-aleatoria",
        resave: false,
        saveUninitialized: true,
    })
);

const TOKENS_FILE = "./tokens.json";
let tokensDB = {};
if (fs.existsSync(TOKENS_FILE)) {
    tokensDB = JSON.parse(fs.readFileSync(TOKENS_FILE));
}

function saveTokens() {
    fs.writeFileSync(TOKENS_FILE, JSON.stringify(tokensDB, null, 2));
}

app.get("/oauth/redir/:email", (req, res) => {
    const { email } = req.params;

    if (!email) return res.status(400).send("Email é obrigatório.");
    req.session.email = email;

    const authUrl = oAuth2Client.generateAuthUrl({
        access_type: "offline",
        scope: SCOPES,
        prompt: "consent",
    });

    res.json({ url: authUrl });
});

app.get("/oauth/receive", async (req, res) => {
    const code = req.query.code;
    const email = req.session.email;
    if (!code || !email) return res.send("Erro: sessão expirada ou código inválido.");

    const { tokens } = await oAuth2Client.getToken(code);
    tokensDB[email] = tokens;
    saveTokens();

    res.send(`
    <h2>Autorizado com sucesso!</h2>
    <p>Conta: ${email}</p>
    <a href="/">Voltar</a>
  `);
});

app.get("/emails/:email", async (req, res) => {
    const email = req.params.email;
    const tokens = tokensDB[email];
    if (!tokens) return res.status(400).send("Email não autorizado.");

    oAuth2Client.setCredentials(tokens);
    const gmail = google.gmail({ version: "v1", auth: oAuth2Client });

    try {
        const response = await gmail.users.messages.list({
            userId: "me",
            maxResults: 10,
        });

        const messages = response.data.messages || [];
        const messageData = [];

        for (const msg of messages) {
            const fullMsg = await gmail.users.messages.get({
                userId: "me",
                id: msg.id,
            });

            const headers = fullMsg.data.payload.headers;
            const subject = headers.find((h) => h.name === "Subject")?.value || "(Sem assunto)";
            const from = headers.find((h) => h.name === "From")?.value || "(Desconhecido)";
            messageData.push({ id: msg.id, subject, from });
        }

        res.json(messageData);
    } catch (err) {
        console.error(err);
        res.status(500).send("Erro ao listar emails");
    }
});

app.get("/email/:email/:id", async (req, res) => {
    const { email, id } = req.params;
    const tokens = tokensDB[email];
    if (!tokens) return res.status(400).send("Email não autorizado.");

    oAuth2Client.setCredentials(tokens);
    const gmail = google.gmail({ version: "v1", auth: oAuth2Client });

    try {
        const message = await gmail.users.messages.get({
            userId: "me",
            id,
            format: "full",
        });

        const body = message.data.payload.parts?.find(
            (p) => p.mimeType === "text/html"
        )?.body?.data;

        const htmlBody = body
            ? Buffer.from(body, "base64").toString("utf8")
            : "<p>(Sem conteúdo)</p>";

        res.send(`
      <h2>${id}</h2>
      <div>${htmlBody}</div>
      <a href="/">Voltar</a>
    `);
    } catch (err) {
        console.error(err);
        res.status(500).send("Erro ao carregar email");
    }
});

app.listen(PORT, () => console.log(`🚀 Servidor rodando em http://localhost:${PORT}`));
Arquivo tokens.json

Crie um arquivo JSON vazio, inicializando o objeto JSON conforme o código abaixo.

{}
public/index.html

Crie o arquivo index.html dentro da pasta public. Altere o exemplo abaixo com o e-mail que você utilizará para testar a API. No meu caso, estou utilizando o meu e-mail pessoal para testar.

<!DOCTYPE html>
<html lang="pt-BR">

<head>
    <meta charset="UTF-8" />
    <title></title>
    <style>
        body {
            font-family: Arial;
            margin: 20px;
        }

        input,
        button {
            padding: 8px;
            margin-top: 5px;
        }

        .email-item {
            border-bottom: 1px solid #ccc;
            padding: 5px;
        }

        .email-item:hover {
            background: #f5f5f5;
            cursor: pointer;
        }
    </style>
</head>

<body>
    <section id="auth">
        <button id="authButton">Autenticar</button>
        <button id="loadEmailsBtn">Carregar E-mails</button>
    </section>

    <h2>Emails</h2>
    <div id="emailsList"></div>

    <script>
        const authButton = document.getElementById('authButton');
        const loadEmailsBtn = document.getElementById('loadEmailsBtn');
        const emailsList = document.getElementById('emailsList');

        authButton.onclick = async () => {
            if (!email) return;

            // Nesse exemplo eu estou usando o meu e-mail, altere para o e-mail que você vai logar no oauth
            // qualquer dúvida é só entrar em contato

            try {
                const response = await fetch(`http://localhost:4000/oauth/redir/leandro.edgedigital@gmail.com`, {
                    method: 'GET',
                    credentials: 'include',
                    headers: {
                        'Content-Type': 'application/json',
                    }
                });

                const data = await res.json();
                window.location.href = data.url;
            } catch (error) {
                console.error('Erro:', error);
            }
        };

        loadEmailsBtn.onclick = async () => {
            loadEmails("leandro.edgedigital@gmail.com");
        }

        async function loadEmails(email) {
            const res = await fetch(`/emails/${email}`);
            const emails = await res.json();

            emailsList.innerHTML = emails.map(e => `
        <div class="email-item" onclick="viewEmail('${email}','${e.id}')">
          <strong>${e.subject}</strong><br>
          <small>${e.from}</small>
        </div>
      `).join('');
        }

        async function viewEmail(email, id) {
            window.location.href = `/email/${email}/${id}`;
        }
    </script>
</body>

</html>

Rodando o projeto

Para rodar o projeto, execute o código abaixo dentro da pasta do projeto.

node server.mjs

Ao executar o código acima, você deverá ver a seguinte mensagem em seu terminal/prompt de comando:

node server.mjs

🚀 Servidor rodando em http://localhost:4000

Abra o seu navegador na página http://localhost:4000 e teste clicando em Autenticar.

Após a autenticação, visualize os e-mails de sua caixa de entrada clicando em Carregar E-mails e visualize o conteúdo do e-mail clicando no e-mail ou acessando http://localhost:4000/email/:seu-email-gmail/:id-do-email

Espero que tenham gostado! Se tiver algum erro, é só entrar em contato comigo em meu e-mail leandro.edgedigital@gmail.com! Até!

Posted in

Deixe uma resposta

Descubra mais sobre Blog do Leandro

Assine agora mesmo para continuar lendo e ter acesso ao arquivo completo.

Continue reading