Gmail integration
This page documents precisely what Unified E box asks Google for, why each permission is necessary, and what we do and do not do with the data we receive.
Last updated September 21, 2026
Summary
Unified E box is an external OAuth application. Each member connects their own personal Gmail account through Google’s official consent flow and can withdraw that access at any time. We request three scopes. Two of them are classified by Google as sensitive and one as restricted.
We never handle Google passwords
Scopes we request
Each scope below is requested at the moment a member connects a mailbox, and is shown to them by Google before they approve. The classifications are Google’s own, taken from the published Gmail API scope reference.
https://www.googleapis.com/auth/gmail.modifyrestrictedWhat it permits. Read messages, threads, and mailbox history, and change the labels applied to them. It does not permit permanently deleting messages or bypassing the trash.
Why we need it
- Fetch the messages and threads that the unified inbox displays.
- Run an incremental sync so the inbox reflects the mailbox without re-downloading it.
- Subscribe to mailbox change notifications so new mail appears without constant polling.
- Apply and remove the UNREAD label when a member marks a conversation read or unread.
- Apply and remove the STARRED label when a member stars or unstars a conversation, and show stars applied in Gmail itself.
- Save an email the member is writing as a draft in their Gmail Drafts, update it as they type, and delete it when they send or discard it.
- Download an attachment on demand when a member opens it.
Gmail API methods we call
users.getProfileusers.messages.listusers.messages.getusers.messages.attachments.getusers.history.listusers.threads.modifyusers.drafts.createusers.drafts.updateusers.drafts.deleteusers.watchusers.stopWhat we do not do with it
- Permanently deleting a member's messages.
- Changing Gmail settings, filters, forwarding, or signatures.
- Creating, renaming, or deleting label definitions in the connected mailbox.
https://www.googleapis.com/auth/gmail.sendsensitiveWhat it permits. Send mail as the connected account. It grants no read access on its own.
Why we need it
- Send a reply or a new message that the member composes in the application.
- Thread the reply correctly onto the existing conversation in Gmail.
Gmail API methods we call
users.messages.sendWhat we do not do with it
- Sending mail that a member did not compose and submit.
- Bulk or automated sending on a member's behalf.
https://www.googleapis.com/auth/userinfo.emailsensitiveWhat it permits. Read the email address and the stable account identifier of the signed-in Google Account.
Why we need it
- Identify which mailbox just completed the consent flow, so the resulting credentials are bound to the correct account record.
- Display the connected address on the Accounts page so a member can tell their mailboxes apart.
- Prevent the same mailbox from being connected twice.
Gmail API methods we call
oauth2.userinfo.getWhat we do not do with it
- Reading contacts or any profile field beyond those disclosed here.
https://www.googleapis.com/auth/userinfo.profilenon-sensitiveWhat it permits. Read the basic public profile of the signed-in Google Account: name and profile photo.
Why we need it
- Show each connected mailbox's own profile photo in the mailbox list, so a member can tell their mailboxes apart at a glance.
Gmail API methods we call
oauth2.userinfo.getWhat we do not do with it
- Reading any profile field other than the photo.
- Showing the photo to anyone outside the member's own organization.
https://www.googleapis.com/auth/calendar.eventssensitiveWhat it permits. View and edit events on the calendars the signed-in Google Account can access. It does not permit changing calendar settings or sharing.
Why we need it
- Show the connected account's upcoming events on the Calendar page, beside its mail.
- Create an event, and invite guests to it, when a member schedules one from the Calendar page.
Gmail API methods we call
calendar.events.listcalendar.events.insertWhat we do not do with it
- Changing or deleting events that already exist.
- Reading any calendar other than the account's primary calendar.
- Changing calendar settings, sharing, or access rules.
Scopes we deliberately do not request
Minimum scope is a design constraint, not an afterthought. These are permissions a mail application might plausibly ask for, and the reason we do not.
| Scope | Why we decline it |
|---|---|
https://mail.google.com/ | Grants full IMAP and SMTP access plus permanent deletion. Nothing in the product needs it, and it would let us destroy mail irreversibly. |
https://www.googleapis.com/auth/gmail.readonly | Redundant. The read access we need is already covered by gmail.modify, so requesting both would add a second restricted scope for no additional capability. |
https://www.googleapis.com/auth/gmail.labels | Not requested. We only add and remove Gmail's built-in UNREAD and STARRED labels on existing threads, which gmail.modify already permits. We never create or manage label definitions. |
https://www.googleapis.com/auth/gmail.settings.basic | We never read or change mailbox settings, filters, forwarding rules, or signatures. |
https://www.googleapis.com/auth/contacts | We do not read the Google Contacts address book. Recipients are typed by the member. |
The authorization flow, step by step
- A member selects Connect Gmail inside the workspace. We create a single-use, server-side state token bound to that member, which expires in ten minutes.
- We redirect the member to Google’s consent screen with the three scopes listed above, requesting offline access so that background sync can continue without re-prompting.
- Google shows the member which permissions are being requested and for which account.
- The member approves or denies. If they deny, no tokens are issued and nothing is stored.
- On approval, Google redirects back with an authorization code. We verify the state token, reject anything replayed or expired, and exchange the code for tokens.
- We check that the grant actually includes the scopes the product needs. If Google returned a partial grant, we reject the connection rather than operate with a half-working mailbox.
- We call
oauth2.userinfo.getonce to learn which mailbox just authorized, so the tokens are bound to the correct account record. This is the only trustworthy source of that identity. - Tokens are encrypted with AES-256-GCM and stored. The initial sync begins, and a Gmail watch is registered so future changes arrive as notifications.
How synchronization works
After the first sync, Unified E box does not repeatedly download the mailbox. It registers a Gmail watch and receives a notification when the mailbox changes, then asks Gmail for just the history since the last known point using users.history.list. This keeps our request volume proportional to actual activity rather than to the number of connected accounts, and it respects Gmail API usage limits.
Gmail watches expire after seven days, so a scheduled job renews them. If a member revokes access at Google, the next refresh fails, and we mark the account as requiring re-authorization and stop calling the Gmail API for it.
What we store
We store a working copy of the synced mail so the interface can render and search it quickly. The table below is a complete description of the Gmail-derived data we retain.
| Category | What it includes | Why |
|---|---|---|
| Message content | Subject, snippet, plain-text and HTML bodies, sender and recipient addresses, and timestamps for the messages we sync. | The inbox renders conversations and searches across them without re-fetching from Gmail on every keystroke. |
| Thread metadata | Gmail thread and message identifiers, message counts, read state, and the RFC 5322 headers needed to thread replies correctly. | Keeps the application in sync with Gmail and makes replies land in the right conversation. |
| Attachment metadata | File name, MIME type, and size. Attachment bytes are not stored; they are fetched from Gmail on demand when a member opens one. | Lets the interface list attachments without holding copies of their contents. |
| OAuth credentials | The refresh token and the current access token, encrypted at rest with AES-256-GCM, plus the granted scopes and expiry time. | Maintains the authorized connection so background sync continues without prompting on every request. |
| Account records | The connected Gmail address, Google's stable account identifier, and the connection status. | Identifies the mailbox and surfaces connection problems to the member. |
| Audit records | Which member connected or disconnected a mailbox, and when. | Security review and abuse investigation. |
Attachment contents are not stored
What we write back to Gmail
There are exactly five ways Unified E box changes anything in a connected Google account.
- Read state. When a member marks a conversation read or unread, we add or remove Gmail’s built-in
UNREADlabel on that thread. - Stars. When a member stars or unstars a conversation, we add or remove Gmail’s built-in
STARREDlabel on that thread. - Drafts. While a member writes an email, we save it in their Gmail Drafts with
users.drafts.createand keep it current withusers.drafts.update. When they send or discard it, we remove that draft withusers.drafts.delete. We only touch drafts we created. - Sending. When a member writes a reply or a new message and submits it, we send it through
users.messages.sendfrom their own connected account. - Calendar events. When a member creates an event on the Calendar page, we add it to that account’s primary Google Calendar with
calendar.events.insert, inviting the guests they list. We never change or delete existing events.
We do not delete mail, move it to trash, archive it in Gmail, create or modify label definitions, or alter mailbox settings. The scopes we hold do not permit permanent deletion, and we did not request one that would.
Disconnecting
A member can disconnect a mailbox from the Accounts page at any time. When they do, we ask Google to revoke the refresh token and we delete the stored credentials outright. After that we cannot call the Gmail API for that mailbox at all. They can equally revoke us from their Google Account permissions page, which has the same effect on our access.
Disconnecting is not the same as deleting
Limited Use
Unified E box’s use of information received from Google APIs adheres to the Google API Services User Data Policy, including the Limited Use requirements. In practice that means Gmail data is used only to provide the features described on this page, it is not transferred except as needed to run those features or to meet a legal obligation, it is never used for advertising, and it is never sold.
Human access to message content
Our staff do not read members’ Gmail message content. The narrow exceptions are the ones the policy allows: when a member explicitly asks us to look at a specific message to resolve a support problem, when it is necessary to investigate a security incident or abuse, or when we are legally required to. Any such access is limited to what the situation requires.
Verification status
Because gmail.modify is a restricted scope, this application is subject to Google’s OAuth verification process, which includes an independent security assessment for applications that keep restricted-scope data. We have designed the application to meet those requirements and are submitting it for review. We do not claim to be approved, verified, or certified by Google, and we will not describe ourselves that way unless and until that status is actually granted.
Reviewers may also find the OAuth review notes useful; they collect the scope justifications, the demo walkthrough, and our contact details in one place.