In this post, I’ll walk you through how to build a Chrome Extension that connects to your Gmail account, reads emails, and sends the email content (subject, body, and attachments) to an external API—like a CRM, file management tool, or custom backend.

This is a real-world use case from one of my recent projects: a Gmail extension that sends emails and documents to a system called Exchange Center.

Let’s dive in. 🚀

Tools & Prerequisites

Before we begin, here’s what you’ll need:

  • A Google Developer Project with Gmail API enabled
  • Your OAuth Client ID
  • Basic knowledge of JavaScript / React (optional but helpful)
  • Familiarity with Chrome Extensions (Manifest V3)

Step 1: Set Up Your Chrome Extension

Create the base extension folder with the following files:

manifest.json

{
  "manifest_version": 3,
  "name": "Gmail Saver",
  "version": "1.0",
  "description": "Save Gmail emails to an external system.",
  "permissions": ["identity", "scripting"],
  "host_permissions": ["https://mail.google.com/", "https://www.googleapis.com/*"],
  "action": {
    "default_popup": "popup.html",
    "default_icon": "icon.png"
  },
  "oauth2": {
    "client_id": "YOUR_CLIENT_ID.apps.googleusercontent.com",
    "scopes": ["https://www.googleapis.com/auth/gmail.readonly"]
  },
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [
    {
      "matches": ["https://mail.google.com/*"],
      "js": ["content.js"],
      "run_at": "document_idle"
    }
  ]
}

Step 2: Authenticate with Google

In your background.js, use chrome.identity.getAuthToken() to get the access token:

chrome.runtime.onInstalled.addListener(() => {
  console.log("Gmail Saver Extension Installed");
});

function authenticate(callback) {
  chrome.identity.getAuthToken({ interactive: true }, function (token) {
    if (chrome.runtime.lastError) {
      console.error(chrome.runtime.lastError);
      return;
    }
    callback(token);
  });
}

Step 3: Fetch Emails from Gmail API

Use the Gmail API to get a list of messages and read their contents.

function fetchEmails(token) {
  fetch("https://www.googleapis.com/gmail/v1/users/me/messages?maxResults=5", {
    headers: { Authorization: `Bearer ${token}` }
  })
    .then((res) => res.json())
    .then((data) => {
      data.messages.forEach((msg) => {
        fetch(`https://www.googleapis.com/gmail/v1/users/me/messages/${msg.id}`, {
          headers: { Authorization: `Bearer ${token}` }
        })
          .then((res) => res.json())
          .then((messageDetail) => {
            const subjectHeader = messageDetail.payload.headers.find(
              (h) => h.name === "Subject"
            );
            const subject = subjectHeader ? subjectHeader.value : "(No Subject)";
            const body = getEmailBody(messageDetail.payload);
            console.log("Subject:", subject);
            console.log("Body:", body);
          });
      });
    });
}

function getEmailBody(payload) {
  const encodedBody =
    payload.parts?.[0]?.body?.data || payload.body?.data || "";
  return decodeURIComponent(escape(window.atob(encodedBody.replace(/-/g, "+").replace(/_/g, "/"))));
}

Step 4: Send Email Content to Your API

Once you have the subject and body, send it to your backend system:

function sendToExchangeCenter(subject, body) {
  fetch("https://your-api.com/save-email", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ subject, body })
  })
    .then((res) => res.json())
    .then((response) => console.log("Saved to system", response))
    .catch((err) => console.error("Save failed", err));
}

Step 5: Inject Button into Gmail UI

Let’s make this more user-friendly by adding a button directly into Gmail threads.

In content.js:

function addSaveButton() {
  const container = document.querySelector("div[aria-label='More']");
  if (!container || document.getElementById("saveEmailButton")) return;

  const btn = document.createElement("button");
  btn.innerText = "Save Email";
  btn.id = "saveEmailButton";
  btn.style = "margin-left: 10px; background: #1a73e8; color: white; padding: 6px 12px; border: none; border-radius: 4px;";

  btn.onclick = () => {
    chrome.runtime.sendMessage({ type: "SAVE_EMAIL" });
  };

  container.parentNode.appendChild(btn);
}

setInterval(addSaveButton, 3000);

Handle the message in your background.js:

chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
  if (msg.type === "SAVE_EMAIL") {
    authenticate((token) => {
      fetchEmails(token);
    });
  }
});

Step 6: Security & API Considerations

  • Use HTTPS for your API
  • Never store Gmail access tokens long-term on the client
  • Respect Google’s API usage limits and user privacy

Conclusion

You now have a fully working Chrome Extension that:

  • Authenticates using Gmail OAuth
  • Reads and parses Gmail content
  • Sends data to your backend system
  • Injects a save button into the Gmail UI

This can be extended to support:

  • Attachments
  • Filtering by labels
  • Batch processing
  • CRM integration

📣 Need Help with a Custom Gmail Extension?

I specialize in building Chrome extensions, custom email automation, and full-stack tools for businesses. If you’re looking to streamline your email workflows — contact me here: https://navaneethm.in/get-in-touch/

Leave a Reply

Your email address will not be published. Required fields are marked *