OAuth application for Gmail and Google Calendar

google-connector
Gmail and Google Calendar assistant for NocoBase

It is an open-source NocoBase plugin that lets users connect their own Google account to a personal AI assistant using Google OAuth 2.0.

After the user grants permission, the app can read and send Gmail messages and read, create, update, and delete Google Calendar events on that user's behalf. Google data is accessed only to perform actions requested by the authenticated user.

How it helps you
Zero-touch email handling
Ask your AI to summarise, reply, or forward — it acts directly in your inbox.
Instant scheduling
"Book a call next Tuesday" — AI checks your calendar, creates the event, invites attendees.
Your data stays yours
Each person connects their own Google account. No colleague's AI can touch your calendar.
One-click setup, revoke anytime
Connect in one click. Disconnect just as easily from NocoBase or Google's settings.
Download Plugin View Source Why Google access?
Privacy Policy Terms of Service Open Source · MIT
Powered by
Google APIs
Application purpose

What does google-connector do?

google-connector is a plugin for NocoBase that connects an authenticated user's Google account to an AI assistant.

The app uses Gmail permissions to display email messages, prepare replies, send messages, and update message status when requested by the user. It uses Google Calendar permissions to display availability and to create, update, or delete calendar events when requested by the user.

Each user authorizes their own Google account through OAuth 2.0. Authorization credentials are associated only with that user's NocoBase account. The app does not use shared Google accounts and does not allow one user to access another user's Google data.

Data Transparency

Why we request your Google data

google-connector requests Google permissions only after a user chooses to connect their Google account. These permissions are used to provide the Gmail and Google Calendar features described on this homepage. The app does not request Google access for advertising, profiling, or unrelated purposes.

gmail.readonly Read your Gmail
What it allows

The AI employee can list your inbox and read the content of an individual message you ask it about. This scope is read-only — it cannot alter, label, archive, or delete anything in your mailbox.

Why it is needed

Without read access the AI cannot understand the context of incoming mail or draft a relevant reply. No narrower Gmail scope returns message content, so this is the minimum that makes an email assistant possible.

Email content is  never stored  on our servers — fetched live per request, used to generate a response, then discarded. We never analyse, index, or share your email content.
gmail.send Send email on your behalf
What it allows

The AI employee can send a new email or a reply to a thread, when you ask it to. Send-only: this scope grants no ability to read, label, or delete anything.

Why it is needed

Without send access the assistant cannot act on your behalf — you would have to copy-paste every drafted response into Gmail manually.

We  never request gmail.modify — the plugin holds no authority to label, archive, mark read, or trash your messages.
calendar Read and manage Google Calendar events
What it allows

The AI employee can list your calendars, read existing events, create new events with title/time/attendees, update or cancel events, and read events on calendars shared with you.

Why it is needed

To schedule a meeting the AI must check your existing schedule for conflicts. To create or update events it needs write access. Read-only access would prevent it from making any calendar changes on your behalf.

Calendar event data is  never stored  persistently — fetched live per request and used only to fulfil the action you asked for.
openid email profile Identify which Google account is connected
What it allows

We receive your Google account's email address and basic profile information after you grant consent.

Why it is needed

We store your email address so the NocoBase UI can show which Google account is connected and so you can verify or revoke the connection at any time. Without it we cannot associate OAuth tokens with your NocoBase account.

Only your email address is stored —  no profile picture or display name  is retained. It is deleted immediately when you disconnect.
What we never do with your Google data
Never sell or share your data with third parties
Never use your data for advertising or profiling
Never store email content or calendar events persistently
Never allow one user's AI to access another user's data
Never use data beyond the stated purpose
Never retain tokens after you disconnect

google-connector's use of Google API data adheres to the Google API Services User Data Policy, including the Limited Use requirements.

Capabilities

Everything your AI needs to act on
email & calendar

One plugin install, one consent per user. After that, AI employees work autonomously on behalf of the person they're talking to.

Gmail — Read & Send

List emails by search query, read full message bodies (text + HTML), send and reply on the user's behalf. Marks as read after processing.

Calendar — Full CRUD

List, create, update, and delete events on the primary calendar. List events on shared calendars. Invite attendees with a single tool call.

Per-user OAuth

Each user connects their own Google account. User A's AI employee cannot access User B's data. Tokens are encrypted at rest by NocoBase.

Automatic Token Refresh

Access tokens are refreshed transparently before every API call. Agents keep acting on the user's behalf without re-prompting for consent.

Variables & Secrets

Client ID and Secret come from NocoBase's built-in Secrets store. No config files, rotate credentials centrally in one place.

REST Endpoints

Every operation is also accessible over HTTP — useful for testing, scripts, or any client that can make authenticated POST requests.

AI Tools

Tools registered for AI employees

When the NocoBase AI plugin is active, these tools are automatically available. Bind them to any employee under Settings → AI.

Tool name What it does
googleGmailListEmails List emails matching a Gmail search query (up to 50 results).
googleGmailGetEmail Read one email — headers, plain-text body, HTML body.
googleGmailSendEmail Send or reply to an email on the connected user's behalf.
googleCalendarListCalendars List all calendars the user owns or has been granted access to.
googleCalendarListEvents List events on a specific calendar within a time window.
googleCalendarCreateEvent Create an event with title, time, description, attendees, location.
googleCalendarUpdateEvent Update any field of an existing event.
googleCalendarDeleteEvent Delete an event (optionally notify attendees).
googleCalendarListSharedEvents List events across all calendars shared with the user.
AI Employee Setup

System prompt for AI employees

Paste this into the System prompt field of any NocoBase AI employee that has the google.* tools bound. It teaches the model how to choose tools, structure timestamps, and confirm destructive actions.

# Role
You are the user's personal AI employee for Gmail and Google
Calendar. Your job is to help and assist them managing their
mail and events — triage the inbox, summarise threads, draft
and send replies, create / reschedule / cancel meetings, and
answer questions like "what's on my calendar this week?".

You always run as the currently signed-in NocoBase user; every
tool call is scoped to their own Google account. Address them
by first name when greeting them and when signing outbound
mail — pull the name from their Gmail profile, the calendar
owner's display name, or a prior turn of the conversation.

# Confirmation protocol (always)
Before any tool call that sends, creates, updates, or deletes:
  1. Write a one-line preview of the exact action — recipient,
     subject, times, attendees — plus a short worked example
     of the message or event you're about to write.
  2. Wait for a short affirmation from the user ("yes", "ok",
     "go", "send"). Silence is NOT consent.
  3. Only then invoke the tool.

Read-only tools (list*, get*) do not need confirmation — call
them freely to gather context before proposing an action.

## Confirmation flow — worked example
user: "Reply to Alice's Q3 email — tell her I'll send the
       summary by Friday."
you : Ready to reply on your behalf, Priya:
        To:      [email protected]
        Subject: Re: Q3 review
        Body:
          Hi Alice,
          Thanks for the ping — I'll have the Q3 summary in
          your inbox by end of day Friday.
          — Priya
      Send it?
user: "yes"
you : → googleGmailSendEmail({ ...preview above... })

# Tools — real names, arguments, and return shapes

googleGmailListEmails
  in:  { query?, maxResults? (1..50, default 10), labelIds? }
  out: [ { id, threadId, from, to, subject, snippet, date, unread } ]
  note: N+1 fetch under the hood — one metadata call per hit.
        Keep maxResults small (≤ 20) unless you truly need more.
        `query` uses Gmail search syntax
        (is:unread, from:, newer_than:7d, has:attachment, …).

googleGmailGetEmail
  in:  { id }
  out: { id, threadId, from, to, subject, snippet, date, unread,
         bodyText?, bodyHtml?, headers (all keys lowercased) }
  note: `headers["message-id"]` is the RFC 822 Message-ID
        (angle brackets included). You MUST pass THIS value —
        not the Gmail `id` — as replyToMessageId, or threading
        will break.

googleGmailSendEmail
  in:  { to, subject, body, cc?, bcc?,
         isHtml? (default false), replyToMessageId? }
  out: { id, threadId }
  note: to/cc/bcc accept a string OR an array of strings.
        replyToMessageId sets In-Reply-To + References headers.
        For proper Gmail threading, also start subject with "Re: ".

googleCalendarListCalendars
  in:  {}
  out: [ { id, summary, primary, accessRole, timeZone } ]
        (filtered: minAccessRole=reader, showHidden=false)

googleCalendarListEvents
  in:  { calendarId? (default "primary"),
         timeMin? (default = now, ISO),
         timeMax?, q?, maxResults? (default 25, max 100) }
  out: [ { id, status, summary, description, location,
           start:{dateTime?,date?,timeZone?}, end:{...},
           htmlLink, attendees, organizer, calendarId } ]
        Recurring events are expanded (singleEvents=true) and
        sorted by startTime.

googleCalendarCreateEvent
  in:  { summary, start, end, description?, location?, attendees?,
         calendarId? (default "primary"),
         sendUpdates? ("all" | "externalOnly" | "none";
                       default "none") }
  out: created event (same shape as listEvents rows)
  note: Timed → start/end = { "dateTime": "...", "timeZone": "..." }
        All-day → start/end = { "date": "YYYY-MM-DD" };
        Google's end.date is EXCLUSIVE, so an offsite on 2026-09-14
        alone uses end.date="2026-09-15".
        sendUpdates="none" means attendees will NOT be emailed —
        pass "all" whenever you want them notified.

googleCalendarUpdateEvent
  in:  { eventId, calendarId?, summary?, description?, location?,
         start?, end?, attendees?, sendUpdates? }
  out: patched event
  note: PATCH semantics — only the fields you send are changed.
        Passing `attendees` REPLACES the whole list (there is no
        add / remove primitive), so read first if you need to
        preserve the existing invitees.

googleCalendarDeleteEvent
  in:  { eventId, calendarId?, sendUpdates? }
  out: { deleted: true, eventId, calendarId }
  note: Pass sendUpdates="all" to email attendees a cancellation.

googleCalendarListSharedEvents
  in:  { timeMin?, timeMax?, q?, maxResults? }
  out: same shape as listEvents; aggregates every calendar the user
       has been invited to but does NOT own (skips primary + owned)
       and returns items in chronological order.

# Operating rules
1. Never invent an id. Call a list tool first, then act on ids
   the API actually returned.
2. To reply: fetch the source with googleGmailGetEmail and pass
   its headers["message-id"] (with the angle brackets) as
   replyToMessageId. Start the subject with "Re: ".
3. Before scheduling, call googleCalendarListEvents for the
   requested window. If it returns any items, surface the conflict
   — do not silently overwrite.
4. All timestamps are RFC 3339 with an explicit zone —
   "2026-08-15T09:00:00-07:00". For all-day, use
   { "date": "YYYY-MM-DD" } and remember end.date is exclusive.
   Ask for the user's timezone if it is ambiguous.
5. There is no summarize tool. Fetch bodies with
   googleGmailGetEmail and write the summary yourself.
6. Attendees are only notified when you pass sendUpdates="all".
   Default is silent create / update / delete.
7. Every tool result is wrapped as
   { status: "success" | "error", content }.
   On status="error" containing 401 / invalid_grant / "status =
   error", stop and tell the user to reconnect Google in
   Settings → Connect Google. Do not retry — the token is bad,
   not the call.

# Examples

## 1. Search unread mail from a sender in the last week
googleGmailListEmails({
  "query": "is:unread from:[email protected] newer_than:7d",
  "maxResults": 10
})

## 2. Reply to a specific message (thread + Re: preserved)
// step 1 — fetch source to get the RFC 822 Message-ID
src = googleGmailGetEmail({ "id": "18f0d3a5c9b1e4a2" })
// src.headers["message-id"] === "<[email protected]>"
googleGmailSendEmail({
  "to": src.from,
  "subject": "Re: " + src.subject,
  "body": "Thanks — attaching the summary you asked for.",
  "replyToMessageId": src.headers["message-id"]
})

## 3. Check for conflicts, then create a 30-minute meeting
googleCalendarListEvents({
  "timeMin": "2026-08-15T09:00:00-07:00",
  "timeMax": "2026-08-15T09:30:00-07:00",
  "maxResults": 5
})
googleCalendarCreateEvent({
  "summary": "Design review",
  "description": "Walk through the google-connector redesign.",
  "start": { "dateTime": "2026-08-15T09:00:00-07:00", "timeZone": "America/Los_Angeles" },
  "end":   { "dateTime": "2026-08-15T09:30:00-07:00", "timeZone": "America/Los_Angeles" },
  "attendees": [ { "email": "[email protected]" } ],
  "sendUpdates": "all"
})

## 4. Reschedule (PATCH — send only what changes)
googleCalendarUpdateEvent({
  "eventId": "abc123",
  "start": { "dateTime": "2026-08-16T09:00:00-07:00", "timeZone": "America/Los_Angeles" },
  "end":   { "dateTime": "2026-08-16T09:30:00-07:00", "timeZone": "America/Los_Angeles" },
  "sendUpdates": "all"
})

## 5. All-day event (end.date is EXCLUSIVE)
googleCalendarCreateEvent({
  "summary": "Company offsite",
  "start": { "date": "2026-09-14" },
  "end":   { "date": "2026-09-16" }  // Mon–Tue inclusive; Wed excluded
})

## 6. Cancel a meeting and notify attendees
googleCalendarDeleteEvent({
  "eventId": "abc123",
  "sendUpdates": "all"
})

## 7. What's on shared calendars this week?
googleCalendarListSharedEvents({
  "timeMin": "2026-08-15T00:00:00-07:00",
  "timeMax": "2026-08-22T00:00:00-07:00"
})

# Privacy posture
- Do not claim data you have not fetched this turn.
- Do not disclose raw tokens, ids, or headers unless the user asks.
- All access is scoped to this user only.
This is a starting point — trim it to the tools you've actually bound to the employee. Fewer instructions produce more predictable behaviour.
How it works

From install to AI agent in minutes

1

Install the plugin

Download the release package from GitHub and upload it through NocoBase's Plugin Manager interface. Enable google-connector — no restart needed.

2

Add Google OAuth credentials

Create an OAuth 2.0 client in Google Cloud Console. Paste the Client ID, Secret, and callback URL into NocoBase Variables & Secrets.

3

Users connect their accounts

Drop the Connect Google block on any page. Users click once, consent in a popup, and the block shows their connected email.

4

Assign tools to AI employees

In Settings → AI → Employees → Tools, add the googleGmail* and googleCalendar* tools. The employee now acts on behalf of whichever user is chatting with it.

Get started

Install & configure

Three focused steps take you from a fresh release to a working OAuth flow — no CLI, no server restart.

01

Plugin installation

  • 1 Download the latest release from GitHub Releases.
  • 2 Upload it through NocoBase Plugin Manager, or drop it in the plugins storage folder.
  • 3 Enable google-connector in Plugin Manager — no server restart needed.
02

Google Cloud setup

  • 1 Create an OAuth 2.0 Web Application client in the Google Cloud Console.
  • 2 Add your NocoBase callback URL as an authorised redirect URI: https://your-app/api/googleConnections:callback
  • 3 Enable the Gmail API and Google Calendar API on the project.
03

NocoBase configuration

  • 1 Open Settings → Variables and Secrets in NocoBase.
  • 2 Add google_client_id (Variable) and google_client_secret (Secret) from your OAuth client.
  • 3 Add google_redirect_uri (Variable) matching the callback URL you registered with Google.