{"id":"6a19b918bdf8b7d4b2a9b6a9","title":"2026 05 29 Gmail Inbox Setup","path":"how-to/technical-articles/2026-05-29-gmail-inbox-setup","contentMarkdown":"# 29-May-2026 — Setting up a Gmail inbox for committee replies\n_____\n\n## Introduction\n- This guide walks through connecting a Gmail account to NGX so that replies sent to a committee role address are routed to the correct person and can be replied to using the correct identity for the committee role.\n- The inbox for your website can be found at `admin/inbox`. Below is a screenshot of the inbox view showing conversations on the left with a preview of the threads associated with that conversation on the right. \n- In order to get the benefits of this new feature, there's a bit of setup to do (see [here](https://ngx-ramblers.org.uk/how-to/technical-articles/2026-05-29-gmail-inbox-setup/notes) for why) and unfortunately it's a little bit involved but it's worth it! The rest of this article is all about what you need to do to get it configured.\n\n> **Note:** There is now a simpler alternative that needs no Gmail account at all: see [Setting up direct-to-inbox for committee replies](https://ngx-ramblers.org.uk/how-to/technical-articles/2026-07-09-direct-inbox-setup). This Gmail route remains fully supported — pick whichever suits your group.\n\n![](https://ngx-ramblers.org.uk/api/aws/s3/site-content/1e11cc5b-d3ae-4cef-82ed-bc54a7cf5c64.jpeg)\n\n### The work splits into three parts\n\n1. Create a dedicated Gmail account for the role mailbox (free).\n2. Create an OAuth client in Google Cloud and authorise the scope NGX needs.\n3. Paste the OAuth credentials into NGX, then connect the mailbox.\n\nMost ongoing configuration happens inside NGX. The only unavoidable manual steps in Google are creating the OAuth client once, and completing Google's consent screen for each connected mailbox.\n\n## Before you start\n\nYou need:\n\n- Member administrator access to the NGX site you are configuring.\n- A Google account to own the Google Cloud project. If you plan to connect several group mailboxes over time, own the Cloud project from one central Google account and add each group's Gmail as a test user, rather than creating a separate project per group. For a single mailbox, owning the project from that group's Gmail account is fine and you can consolidate later.\n- **A separate Incognito / private browsing window for each Google sign-in.** This guide signs you into Google twice — into the Cloud console as the account that owns the project, and into the consent screen as the dedicated mailbox account. If you are signed into several Google accounts at once, Google quietly picks the wrong one and you will not notice until something has been created under the wrong account. Open a fresh Incognito / private window and sign in as the specific account each step needs; it also keeps the two accounts cleanly apart.\n\n## Part 1 — Create the dedicated Gmail account\n\nCreate a free Gmail account that will receive the committee mail, for our example group that is `examplewalkinggroup@gmail.com`.\n\nWhen Google asks what the account is for, choose **For my personal use**. That is the option that creates a free `@gmail.com` account. **For work or my business** pushes you toward Google Workspace, which is a paid product, and **For my child** sets up a supervised account.\n\n## Part 2 — Create the OAuth client in Google Cloud\n\nGo to [console.cloud.google.com](https://console.cloud.google.com/). Every link below opens straight on the page you need with your active project pre-selected.\n\n### Create the project and enable the Gmail API\n\n1. [Create a new project](https://console.cloud.google.com/projectcreate) named something obvious, for example `ngx-ramblers-inbox`. As you type the name, Google generates a **Project ID** just beneath it — a globally unique string, usually your name plus a number (for example `ngx-ramblers-inbox-461210`). This is *not* the same as the project name, and it is the value you will paste into the **Pub/Sub setup** step later and append as `?project=<your-project-id>` on the links in this guide. Before you select **Create**, choose **Edit** beside the generated ID if you want to set your own (while it is still available), and note the ID down — you cannot change it after creation. (If you need it again later, the project picker in the blue bar at the top of the console lists each project's name and ID side by side, or [IAM & Admin → Settings](https://console.cloud.google.com/iam-admin/settings) shows the Project ID, name and number together.)\n2. [Enable the Gmail API](https://console.cloud.google.com/flows/enableapi?apiid=gmail.googleapis.com) — the link opens on the Gmail API itself; confirm the project and select **Enable**. (Manual equivalent: **APIs & Services → Library → Gmail API → Enable**.)\n\n![](https://ngx-ramblers.org.uk/api/aws/s3/site-content/04407b34-f2c9-4a4a-8b5b-829b5b8e3dab.png)\n\n*Confirm the project, then enable the Gmail API. When it finishes you see “You have successfully enabled Gmail API”.*\n\n### Complete the Google Auth Platform wizard\n\nGoogle has reorganised what used to be called the \"OAuth consent screen\" into the **Google Auth Platform**. The first time you open [the Google Auth Platform](https://console.cloud.google.com/auth/overview) you get a short wizard: **App Information → Audience → Contact Information → Finish**. It no longer asks for scopes or test users inline; those are set afterwards from the left-hand menu.\n\n![](https://ngx-ramblers.org.uk/api/aws/s3/site-content/516f7497-e4bf-482a-b9af-53f20fc1407c.png)\n\n*The Google Auth Platform Overview before anything is configured — select “Get started” to open the wizard.*\n\nWork through the wizard:\n\n1. **App Information** — App name `NGX Ramblers Inbox`, and a user support email.\n2. **Audience** — choose **External**.\n3. **Contact Information** — your email address, for Google's notices.\n4. **Finish** — agree to the policy, then **Create**.\n\n![](https://ngx-ramblers.org.uk/api/aws/s3/site-content/64977358-0639-4ce9-9c0d-552ce9c7c7fa.png)\n\n*Wizard step 1, App Information: an app name and a user support email.*\n\n![](https://ngx-ramblers.org.uk/api/aws/s3/site-content/05727cc0-2f1d-4d20-b431-34039bc4eee8.png)\n\n*Wizard step 2, Audience: choose External.*\n\n![](https://ngx-ramblers.org.uk/api/aws/s3/site-content/a1cf1fcb-549e-4e47-b93f-14909d774afc.png)\n\n*Wizard step 3, Contact Information: an email address for Google’s notices.*\n\n![](https://ngx-ramblers.org.uk/api/aws/s3/site-content/660a2721-28e8-487c-a66c-ebcf587e7b86.png)\n\n*Wizard step 4, Finish: agree to the policy, then Create.*\n\n### Set the audience, scope and client\n\nWith the project created, use the left-hand menu of the Google Auth Platform:\n\n1. **[Audience](https://console.cloud.google.com/auth/audience)** — the page shows two sections to confirm, in this order: **Publishing status**, which starts as **Testing** (you publish it to production once the mailbox is working — see *Keep the connection alive* near the end of this guide, otherwise the connection dies after seven days), then **User type**, which should read **External**. Below those, under **Test users**, select **+ Add users** and add the dedicated Gmail address (`examplewalkinggroup@gmail.com` for our example group) and your own Google address. While the app is in Testing, only listed test users can complete consent, so an account that is not listed here will be refused.\n\n![](https://ngx-ramblers.org.uk/api/aws/s3/site-content/af66551b-1c0b-470c-99c0-771b7069875b.png)\n\n*Audience: with Publishing status set to Testing and User type External, add each Gmail address under Test users.*\n\n2. **[Data Access](https://console.cloud.google.com/auth/scopes)** — select **Add or remove scopes**, add `https://www.googleapis.com/auth/gmail.modify`, then **Update** and **Save**. This single scope lets NGX list, read, mark as read, and send messages. No broader access is requested.\n\n![](https://ngx-ramblers.org.uk/api/aws/s3/site-content/ce5b0d80-3a4f-4ff7-9939-00f6107a115e.png)\n\n*Data Access → Add or remove scopes: paste https://www.googleapis.com/auth/gmail.modify into “Manually add scopes”, Add to table, then Update.*\n\n![](https://ngx-ramblers.org.uk/api/aws/s3/site-content/4eb7f5b4-90fb-4364-b906-55c580ac1434.png)\n\n*Data Access showing the single gmail.modify scope listed under Gmail scopes.*\n\n3. **[Clients](https://console.cloud.google.com/auth/clients)** — select **[Create client](https://console.cloud.google.com/auth/clients/create)**:\n   - Application type: **Web application**\n   - Name: something like `NGX Ramblers Inbox - Example Walking Group`\n   - Under **Authorised redirect URIs**, add the URI that matches the environment you are connecting from (see the table below).\n   - Select **Create**. A dialog shows the **Client ID** and **Client secret** — copy **both** now. The Client secret appears **only** in this dialog; once you close it, Google will not show it again.\n\n![](https://ngx-ramblers.org.uk/api/aws/s3/site-content/049f417e-73f9-4cac-9c43-aa2eefb0082f.png)\n\n*The OAuth Overview once the wizard is complete and before any client exists — “Create OAuth client” begins the next step.*\n\n![](https://ngx-ramblers.org.uk/api/aws/s3/site-content/02b6a3ad-d89e-4eeb-9081-87ddec3edfbd.png)\n\n*Clients → Create client: Application type Web application, a name, and the Authorised redirect URI for the environment you are connecting from.*\n\n![](https://ngx-ramblers.org.uk/api/aws/s3/site-content/0d9b9122-7771-4158-af3a-593335e37714.png)\n\n*The “OAuth client created” dialog shows the Client ID and secret — copy both before closing it, as the secret is shown only once.*\n\nIf you closed the dialog without copying the secret, you do not need to start over:\n\n- On the [Clients](https://console.cloud.google.com/auth/clients) list, open the client (click its name, or the pencil icon under **Actions**).\n- The **Client ID**, **Status** and **Client secrets** live in an **Additional information** panel to the **right** of the Name/redirect-URI form. If you cannot see it, **maximise the browser window** — on a narrow window (an Incognito window often opens small) Google moves that panel **below** the Save button instead of beside the form.\n- Under **Client secrets**, select **+ Add secret**, then copy the value it generates (again, shown once). The Client ID is always visible here; only the secret is one-time.\n\n![](https://ngx-ramblers.org.uk/api/aws/s3/site-content/6138d7d1-4a4a-4398-93e6-fde1bf92d7d7.png)\n\n*If you closed the dialog, open the client and use the “Additional information” panel on the right; under Client secrets select “+ Add secret” to generate a new one.*\n\n### Choosing the redirect URI\n\nThe redirect URI is where Google sends the browser back after consent. It must point at the NGX deployment you are connecting from, and it must match exactly on both sides.\n\n| Where you are connecting from | Authorised redirect URI |\n| --- | --- |\n| Local development | `http://localhost:4200/api/inbox/oauth/callback` |\n| Staging (www.ngx-ramblers.org.uk) | `https://www.ngx-ramblers.org.uk/api/inbox/oauth/callback` |\n| Your group's live site | `https://<your-domain>/api/inbox/oauth/callback` (for our example group, `https://examplewalkers.org.uk/api/inbox/oauth/callback`) |\n\nYou can register more than one on the same client, so a single OAuth client can serve several deployments.\n\n## Part 3 — Configure NGX and connect the mailbox\n\n### Enter the OAuth credentials\n\nAs a member administrator, open **Admin → Mail Settings**, open the **Inbox** tab (with the inbox provider set to **Gmail account**), and scroll to the Gmail settings, then enter:\n\n| Field | Value |\n| --- | --- |\n| OAuth Client ID | the client ID from Google Cloud |\n| OAuth Client Secret | the client secret from Google Cloud |\n| OAuth Redirect URI | the exact redirect URI you registered on the client |\n\nSave the system configuration. The values are held in the database and read server-side; there is nothing to deploy or inject as an environment variable. The client secret is hidden from non-administrators. If any of the three values is missing, NGX refuses to start the consent flow and points you back to this screen.\n\n### Connect the Gmail inbox\n\nOpen **Admin → Mail Settings** as a member administrator, open the **Inbox** tab, scroll to the Gmail settings, and go to the **Connected Gmail accounts** step. This is also where Google returns you after the consent step:\n\n![](https://ngx-ramblers.org.uk/api/aws/s3/site-content/d7cb8667-425e-4c4e-8bc1-4b1343185e3d.png)\n\n*In NGX, the Connected Gmail accounts step: select “Add Gmail inbox”, complete Google consent, and the mailbox shows as connected.*\n\n1. Select **Add Gmail inbox** (or **Connect Gmail** on an existing unconnected mailbox). NGX records the mailbox and redirects you to Google consent.\n2. Sign in as the dedicated Gmail account. If you use more than one Google account, do this in a fresh Incognito / private window (see *Before you start*) so Google does not sign you in as the wrong one.\n3. Because the app is in Testing, Google shows a **\"Google hasn't verified this app\"** warning. This is expected. Select **Advanced**, then **Go to NGX Ramblers Inbox (unsafe)**, and approve.\n\n![](https://ngx-ramblers.org.uk/api/aws/s3/site-content/f626acaf-6a81-4ded-9dd7-395562e768cb.png)\n\n*Because the app is in Testing, Google shows a “Google hasn’t verified this app” warning; as a listed test user, continue past it.*\n\n![](https://ngx-ramblers.org.uk/api/aws/s3/site-content/2bd2181d-3781-4c48-a662-559279fa60ca.png)\n\n*Approve the gmail.modify access request to return to NGX, where an encrypted refresh token is stored.*\n\n4. Google returns you to NGX. The mailbox flips from \"New Gmail inbox\" to the connected email address, and an encrypted refresh token is stored.\n\nAssigning further committee roles to an already connected mailbox does not require another consent flow.\n\n**Before you rely on this mailbox, publish the app to production.** The refresh token you have just stored expires after seven days while the app is in Testing. The *Keep the connection alive* section below covers this — it is the step most people miss.\n\n### Map roles and configure forwarding\n\nStill in the **Gmail Inbox** section (**Mail Settings → Inbox**):\n\n- Set the **Committee mailbox access** policy per connected inbox. **All committee role mailboxes** lets any committee user view and reply to roles mapped to that inbox. **Assigned roles only** restricts each role to the committee members assigned to it.\n- Use **Role mailbox assignments** to point committee role addresses at the relevant Gmail inbox.\n- Select **Configure forwarding** on a connected inbox to create or update the Cloudflare Email Routing rules. Cloudflare sends a verification email to the Gmail destination; confirm it in Gmail, then select **Configure forwarding** again to apply the rules.\n\n![](https://ngx-ramblers.org.uk/api/aws/s3/site-content/3b6e6232-f508-4a42-add9-2339562c8d9c.png)\n\n*After confirming the Cloudflare verification email in the Gmail account, routing to the mailbox is verified.*\n\n### Delivery: pull or push\n\nEach connected mailbox has a **Delivery** setting on the **Connected Gmail accounts** step:\n\n- **Pull** (default) polls Gmail every 30 seconds. No extra setup - this is the lowest-friction option and all you need for a first test.\n- **Push** uses Gmail's real-time notifications via a Google Cloud Pub/Sub topic. NGX provisions this for you in one click rather than by hand:\n  1. Add the `https://www.googleapis.com/auth/cloud-platform` scope to your OAuth client, on the same **[Data Access](https://console.cloud.google.com/auth/scopes)** screen where you added `gmail.modify`. The one-click setup signs in with this scope.\n  2. On the **Pub/Sub setup** step, enter a Google Cloud project ID you own and a topic name (default `ngx-inbox-events`), then select **Run Google Cloud setup**. After Google's consent screen, NGX enables the Gmail and Pub/Sub APIs, creates the topic, grants `gmail-api-push@system.gserviceaccount.com` the Pub/Sub Publisher role, and creates a push subscription pointed at NGX's push-receiver URL - no manual Cloud console steps.\n  3. Back on the mailbox, set **Delivery** to **Push** and select **Apply push**. Switching back to **Pull** stops the watch and resumes polling.\n\nThe push registration expires after seven days; a daily job renews it and catches up on anything missed, so push degrades safely even if a notification is dropped.\n\n## Keep the connection alive: publish the app to production\n\nWhile the app's **Publishing status** is **Testing**, Google expires the stored refresh token **after seven days**, used or not. When that happens the mailbox stops importing, its status shows a revoked token, and the error is `invalid_grant`. This is the most common reason a working inbox goes quiet about a week after it was first connected, and it is nothing you did wrong — it is Google's policy for an app that is still in Testing.\n\nThe fix is to take the app out of Testing once you have confirmed the mailbox connects and imports mail:\n\n1. Open **[Audience](https://console.cloud.google.com/auth/audience)** (sign in as the account that owns the project, in a private window if you juggle several Google accounts).\n2. Under **Publishing status**, select **Publish app** and confirm the dialog.\n3. The status changes to **In production**, and refresh tokens stop expiring. Reconnect the mailbox once more to replace the short-lived seven-day token with a durable one.\n\nWhat you do *not* need to do:\n\n- **You do not need to complete verification.** An unverified app in production still issues working, non-expiring tokens for your own mailbox. The \"Google hasn't verified this app\" warning still appears at consent, and you click past it exactly as before. Verification only matters if you publish a logo or open the app to the wider public.\n- **Do not upload an app logo** on the **Branding** screen. A logo forces the app into mandatory verification. For a role mailbox you want it published but unverified, so leave the logo blank.\n\nThis is a different seven-day clock from the push watch described under *Delivery: pull or push*. Publishing the app fixes the **token**; the push **watch** renews itself automatically. A mailbox you intend to keep running needs both, which in practice means it needs the app published to production.\n\n## Troubleshooting\n\n**Error 400: redirect_uri_mismatch** on the Google sign-in screen. The redirect URI NGX sent does not exactly match any Authorised redirect URI on the OAuth client. The two values must be identical down to the scheme (`http` vs `https`), host, port, path, and the absence of a trailing slash. Compare the **OAuth Redirect URI** saved in NGX (**Mail Settings → Inbox**, Gmail Inbox section) against the **Authorised redirect URIs** on the client in [Google Cloud → Clients](https://console.cloud.google.com/auth/clients), fix whichever is wrong, save, and retry. The failed Google URL contains a `redirect_uri=` parameter showing exactly what NGX sent.\n\n**\"Google Inbox OAuth client is not configured.\"** One or more of Client ID, Client Secret or Redirect URI is blank in the **Gmail Inbox** section (**Mail Settings → Inbox**). Fill all three and save.\n\n**\"Access blocked\" / the account is refused at consent.** The Gmail account you are signing in as is not listed as a test user while the app is in Testing. Add it under [Google Auth Platform → Audience → Test users](https://console.cloud.google.com/auth/audience).\n\n![](https://ngx-ramblers.org.uk/api/aws/s3/site-content/f10e7b09-20fa-494a-9825-a3098be61fee.png)\n\n*“Access blocked … Error 403: access_denied” means the account signing in is not listed as a Test user while the app is in Testing.*\n\n**Google did not return a refresh token.** This happens if the account previously authorised the app. Remove the app's access in the Google account's security settings, then retry the consent flow.\n\n**Replies stop arriving.** The usual cause is the seven-day Testing-mode token expiry described under *Keep the connection alive*: while the app is in **Testing**, Google revokes the refresh token about a week after it was issued, and the mailbox status shows a revoked token with the error `invalid_grant`. Publish the app to production so this stops recurring, then reconnect the mailbox to mint a fresh, durable token. (A token can also be revoked if the Gmail password changes or Google tightens a policy review.) A daily health check pings each connected mailbox, and when it finds a revoked token it now sends a push notification to the inbox so you are not left guessing. Re-scanning the general mailbox no longer clears existing threads when the token is broken — it reports the error and leaves your mail in place — and reconnecting re-imports anything missed and restarts push delivery straight away.\n\n**Recovery steps:**\n\n1. If the app's publishing status is still **Testing**, publish it to production first (see *Keep the connection alive*), otherwise the replacement token will expire again after seven days.\n2. In NGX, open the **Gmail Inbox** section (**Mail Settings → Inbox**) and find the affected mailbox under **Connected Gmail accounts**.\n3. Select **Reconnect** and complete Google consent as the dedicated Gmail account. If you are signed into several Google accounts, do this in a fresh Incognito / private window so Google does not pick the wrong one.\n4. The mailbox returns to connected, the backlog re-imports, and push delivery restarts automatically.","contentHtml":"<h1>29-May-2026 — Setting up a Gmail inbox for committee replies</h1>\n<hr>\n<h2>Introduction</h2>\n<ul>\n<li>This guide walks through connecting a Gmail account to NGX so that replies sent to a committee role address are routed to the correct person and can be replied to using the correct identity for the committee role.</li>\n<li>The inbox for your website can be found at <code>admin/inbox</code>. Below is a screenshot of the inbox view showing conversations on the left with a preview of the threads associated with that conversation on the right. </li>\n<li>In order to get the benefits of this new feature, there&#39;s a bit of setup to do (see <a href=\"https://ngx-ramblers.org.uk/how-to/technical-articles/2026-05-29-gmail-inbox-setup/notes\">here</a> for why) and unfortunately it&#39;s a little bit involved but it&#39;s worth it! The rest of this article is all about what you need to do to get it configured.</li>\n</ul>\n<blockquote>\n<p><strong>Note:</strong> There is now a simpler alternative that needs no Gmail account at all: see <a href=\"https://ngx-ramblers.org.uk/how-to/technical-articles/2026-07-09-direct-inbox-setup\">Setting up direct-to-inbox for committee replies</a>. This Gmail route remains fully supported — pick whichever suits your group.</p>\n</blockquote>\n<p><img src=\"https://ngx-ramblers.org.uk/api/aws/s3/site-content/1e11cc5b-d3ae-4cef-82ed-bc54a7cf5c64.jpeg\" alt=\"\"></p>\n<h3>The work splits into three parts</h3>\n<ol>\n<li>Create a dedicated Gmail account for the role mailbox (free).</li>\n<li>Create an OAuth client in Google Cloud and authorise the scope NGX needs.</li>\n<li>Paste the OAuth credentials into NGX, then connect the mailbox.</li>\n</ol>\n<p>Most ongoing configuration happens inside NGX. The only unavoidable manual steps in Google are creating the OAuth client once, and completing Google&#39;s consent screen for each connected mailbox.</p>\n<h2>Before you start</h2>\n<p>You need:</p>\n<ul>\n<li>Member administrator access to the NGX site you are configuring.</li>\n<li>A Google account to own the Google Cloud project. If you plan to connect several group mailboxes over time, own the Cloud project from one central Google account and add each group&#39;s Gmail as a test user, rather than creating a separate project per group. For a single mailbox, owning the project from that group&#39;s Gmail account is fine and you can consolidate later.</li>\n<li><strong>A separate Incognito / private browsing window for each Google sign-in.</strong> This guide signs you into Google twice — into the Cloud console as the account that owns the project, and into the consent screen as the dedicated mailbox account. If you are signed into several Google accounts at once, Google quietly picks the wrong one and you will not notice until something has been created under the wrong account. Open a fresh Incognito / private window and sign in as the specific account each step needs; it also keeps the two accounts cleanly apart.</li>\n</ul>\n<h2>Part 1 — Create the dedicated Gmail account</h2>\n<p>Create a free Gmail account that will receive the committee mail, for our example group that is <code>examplewalkinggroup@gmail.com</code>.</p>\n<p>When Google asks what the account is for, choose <strong>For my personal use</strong>. That is the option that creates a free <code>@gmail.com</code> account. <strong>For work or my business</strong> pushes you toward Google Workspace, which is a paid product, and <strong>For my child</strong> sets up a supervised account.</p>\n<h2>Part 2 — Create the OAuth client in Google Cloud</h2>\n<p>Go to <a href=\"https://console.cloud.google.com/\">console.cloud.google.com</a>. Every link below opens straight on the page you need with your active project pre-selected.</p>\n<h3>Create the project and enable the Gmail API</h3>\n<ol>\n<li><a href=\"https://console.cloud.google.com/projectcreate\">Create a new project</a> named something obvious, for example <code>ngx-ramblers-inbox</code>. As you type the name, Google generates a <strong>Project ID</strong> just beneath it — a globally unique string, usually your name plus a number (for example <code>ngx-ramblers-inbox-461210</code>). This is <em>not</em> the same as the project name, and it is the value you will paste into the <strong>Pub/Sub setup</strong> step later and append as <code>?project=&lt;your-project-id&gt;</code> on the links in this guide. Before you select <strong>Create</strong>, choose <strong>Edit</strong> beside the generated ID if you want to set your own (while it is still available), and note the ID down — you cannot change it after creation. (If you need it again later, the project picker in the blue bar at the top of the console lists each project&#39;s name and ID side by side, or <a href=\"https://console.cloud.google.com/iam-admin/settings\">IAM &amp; Admin → Settings</a> shows the Project ID, name and number together.)</li>\n<li><a href=\"https://console.cloud.google.com/flows/enableapi?apiid=gmail.googleapis.com\">Enable the Gmail API</a> — the link opens on the Gmail API itself; confirm the project and select <strong>Enable</strong>. (Manual equivalent: <strong>APIs &amp; Services → Library → Gmail API → Enable</strong>.)</li>\n</ol>\n<p><img src=\"https://ngx-ramblers.org.uk/api/aws/s3/site-content/04407b34-f2c9-4a4a-8b5b-829b5b8e3dab.png\" alt=\"\"></p>\n<p><em>Confirm the project, then enable the Gmail API. When it finishes you see “You have successfully enabled Gmail API”.</em></p>\n<h3>Complete the Google Auth Platform wizard</h3>\n<p>Google has reorganised what used to be called the &quot;OAuth consent screen&quot; into the <strong>Google Auth Platform</strong>. The first time you open <a href=\"https://console.cloud.google.com/auth/overview\">the Google Auth Platform</a> you get a short wizard: <strong>App Information → Audience → Contact Information → Finish</strong>. It no longer asks for scopes or test users inline; those are set afterwards from the left-hand menu.</p>\n<p><img src=\"https://ngx-ramblers.org.uk/api/aws/s3/site-content/516f7497-e4bf-482a-b9af-53f20fc1407c.png\" alt=\"\"></p>\n<p><em>The Google Auth Platform Overview before anything is configured — select “Get started” to open the wizard.</em></p>\n<p>Work through the wizard:</p>\n<ol>\n<li><strong>App Information</strong> — App name <code>NGX Ramblers Inbox</code>, and a user support email.</li>\n<li><strong>Audience</strong> — choose <strong>External</strong>.</li>\n<li><strong>Contact Information</strong> — your email address, for Google&#39;s notices.</li>\n<li><strong>Finish</strong> — agree to the policy, then <strong>Create</strong>.</li>\n</ol>\n<p><img src=\"https://ngx-ramblers.org.uk/api/aws/s3/site-content/64977358-0639-4ce9-9c0d-552ce9c7c7fa.png\" alt=\"\"></p>\n<p><em>Wizard step 1, App Information: an app name and a user support email.</em></p>\n<p><img src=\"https://ngx-ramblers.org.uk/api/aws/s3/site-content/05727cc0-2f1d-4d20-b431-34039bc4eee8.png\" alt=\"\"></p>\n<p><em>Wizard step 2, Audience: choose External.</em></p>\n<p><img src=\"https://ngx-ramblers.org.uk/api/aws/s3/site-content/a1cf1fcb-549e-4e47-b93f-14909d774afc.png\" alt=\"\"></p>\n<p><em>Wizard step 3, Contact Information: an email address for Google’s notices.</em></p>\n<p><img src=\"https://ngx-ramblers.org.uk/api/aws/s3/site-content/660a2721-28e8-487c-a66c-ebcf587e7b86.png\" alt=\"\"></p>\n<p><em>Wizard step 4, Finish: agree to the policy, then Create.</em></p>\n<h3>Set the audience, scope and client</h3>\n<p>With the project created, use the left-hand menu of the Google Auth Platform:</p>\n<ol>\n<li><strong><a href=\"https://console.cloud.google.com/auth/audience\">Audience</a></strong> — the page shows two sections to confirm, in this order: <strong>Publishing status</strong>, which starts as <strong>Testing</strong> (you publish it to production once the mailbox is working — see <em>Keep the connection alive</em> near the end of this guide, otherwise the connection dies after seven days), then <strong>User type</strong>, which should read <strong>External</strong>. Below those, under <strong>Test users</strong>, select <strong>+ Add users</strong> and add the dedicated Gmail address (<code>examplewalkinggroup@gmail.com</code> for our example group) and your own Google address. While the app is in Testing, only listed test users can complete consent, so an account that is not listed here will be refused.</li>\n</ol>\n<p><img src=\"https://ngx-ramblers.org.uk/api/aws/s3/site-content/af66551b-1c0b-470c-99c0-771b7069875b.png\" alt=\"\"></p>\n<p><em>Audience: with Publishing status set to Testing and User type External, add each Gmail address under Test users.</em></p>\n<ol start=\"2\">\n<li><strong><a href=\"https://console.cloud.google.com/auth/scopes\">Data Access</a></strong> — select <strong>Add or remove scopes</strong>, add <code>https://www.googleapis.com/auth/gmail.modify</code>, then <strong>Update</strong> and <strong>Save</strong>. This single scope lets NGX list, read, mark as read, and send messages. No broader access is requested.</li>\n</ol>\n<p><img src=\"https://ngx-ramblers.org.uk/api/aws/s3/site-content/ce5b0d80-3a4f-4ff7-9939-00f6107a115e.png\" alt=\"\"></p>\n<p><em>Data Access → Add or remove scopes: paste <a href=\"https://www.googleapis.com/auth/gmail.modify\">https://www.googleapis.com/auth/gmail.modify</a> into “Manually add scopes”, Add to table, then Update.</em></p>\n<p><img src=\"https://ngx-ramblers.org.uk/api/aws/s3/site-content/4eb7f5b4-90fb-4364-b906-55c580ac1434.png\" alt=\"\"></p>\n<p><em>Data Access showing the single gmail.modify scope listed under Gmail scopes.</em></p>\n<ol start=\"3\">\n<li><strong><a href=\"https://console.cloud.google.com/auth/clients\">Clients</a></strong> — select <strong><a href=\"https://console.cloud.google.com/auth/clients/create\">Create client</a></strong>:<ul>\n<li>Application type: <strong>Web application</strong></li>\n<li>Name: something like <code>NGX Ramblers Inbox - Example Walking Group</code></li>\n<li>Under <strong>Authorised redirect URIs</strong>, add the URI that matches the environment you are connecting from (see the table below).</li>\n<li>Select <strong>Create</strong>. A dialog shows the <strong>Client ID</strong> and <strong>Client secret</strong> — copy <strong>both</strong> now. The Client secret appears <strong>only</strong> in this dialog; once you close it, Google will not show it again.</li>\n</ul>\n</li>\n</ol>\n<p><img src=\"https://ngx-ramblers.org.uk/api/aws/s3/site-content/049f417e-73f9-4cac-9c43-aa2eefb0082f.png\" alt=\"\"></p>\n<p><em>The OAuth Overview once the wizard is complete and before any client exists — “Create OAuth client” begins the next step.</em></p>\n<p><img src=\"https://ngx-ramblers.org.uk/api/aws/s3/site-content/02b6a3ad-d89e-4eeb-9081-87ddec3edfbd.png\" alt=\"\"></p>\n<p><em>Clients → Create client: Application type Web application, a name, and the Authorised redirect URI for the environment you are connecting from.</em></p>\n<p><img src=\"https://ngx-ramblers.org.uk/api/aws/s3/site-content/0d9b9122-7771-4158-af3a-593335e37714.png\" alt=\"\"></p>\n<p><em>The “OAuth client created” dialog shows the Client ID and secret — copy both before closing it, as the secret is shown only once.</em></p>\n<p>If you closed the dialog without copying the secret, you do not need to start over:</p>\n<ul>\n<li>On the <a href=\"https://console.cloud.google.com/auth/clients\">Clients</a> list, open the client (click its name, or the pencil icon under <strong>Actions</strong>).</li>\n<li>The <strong>Client ID</strong>, <strong>Status</strong> and <strong>Client secrets</strong> live in an <strong>Additional information</strong> panel to the <strong>right</strong> of the Name/redirect-URI form. If you cannot see it, <strong>maximise the browser window</strong> — on a narrow window (an Incognito window often opens small) Google moves that panel <strong>below</strong> the Save button instead of beside the form.</li>\n<li>Under <strong>Client secrets</strong>, select <strong>+ Add secret</strong>, then copy the value it generates (again, shown once). The Client ID is always visible here; only the secret is one-time.</li>\n</ul>\n<p><img src=\"https://ngx-ramblers.org.uk/api/aws/s3/site-content/6138d7d1-4a4a-4398-93e6-fde1bf92d7d7.png\" alt=\"\"></p>\n<p><em>If you closed the dialog, open the client and use the “Additional information” panel on the right; under Client secrets select “+ Add secret” to generate a new one.</em></p>\n<h3>Choosing the redirect URI</h3>\n<p>The redirect URI is where Google sends the browser back after consent. It must point at the NGX deployment you are connecting from, and it must match exactly on both sides.</p>\n<table>\n<thead>\n<tr>\n<th>Where you are connecting from</th>\n<th>Authorised redirect URI</th>\n</tr>\n</thead>\n<tbody><tr>\n<td>Local development</td>\n<td><code>http://localhost:4200/api/inbox/oauth/callback</code></td>\n</tr>\n<tr>\n<td>Staging (<a href=\"http://www.ngx-ramblers.org.uk\">www.ngx-ramblers.org.uk</a>)</td>\n<td><code>https://www.ngx-ramblers.org.uk/api/inbox/oauth/callback</code></td>\n</tr>\n<tr>\n<td>Your group&#39;s live site</td>\n<td><code>https://&lt;your-domain&gt;/api/inbox/oauth/callback</code> (for our example group, <code>https://examplewalkers.org.uk/api/inbox/oauth/callback</code>)</td>\n</tr>\n</tbody></table>\n<p>You can register more than one on the same client, so a single OAuth client can serve several deployments.</p>\n<h2>Part 3 — Configure NGX and connect the mailbox</h2>\n<h3>Enter the OAuth credentials</h3>\n<p>As a member administrator, open <strong>Admin → Mail Settings</strong>, open the <strong>Inbox</strong> tab (with the inbox provider set to <strong>Gmail account</strong>), and scroll to the Gmail settings, then enter:</p>\n<table>\n<thead>\n<tr>\n<th>Field</th>\n<th>Value</th>\n</tr>\n</thead>\n<tbody><tr>\n<td>OAuth Client ID</td>\n<td>the client ID from Google Cloud</td>\n</tr>\n<tr>\n<td>OAuth Client Secret</td>\n<td>the client secret from Google Cloud</td>\n</tr>\n<tr>\n<td>OAuth Redirect URI</td>\n<td>the exact redirect URI you registered on the client</td>\n</tr>\n</tbody></table>\n<p>Save the system configuration. The values are held in the database and read server-side; there is nothing to deploy or inject as an environment variable. The client secret is hidden from non-administrators. If any of the three values is missing, NGX refuses to start the consent flow and points you back to this screen.</p>\n<h3>Connect the Gmail inbox</h3>\n<p>Open <strong>Admin → Mail Settings</strong> as a member administrator, open the <strong>Inbox</strong> tab, scroll to the Gmail settings, and go to the <strong>Connected Gmail accounts</strong> step. This is also where Google returns you after the consent step:</p>\n<p><img src=\"https://ngx-ramblers.org.uk/api/aws/s3/site-content/d7cb8667-425e-4c4e-8bc1-4b1343185e3d.png\" alt=\"\"></p>\n<p><em>In NGX, the Connected Gmail accounts step: select “Add Gmail inbox”, complete Google consent, and the mailbox shows as connected.</em></p>\n<ol>\n<li>Select <strong>Add Gmail inbox</strong> (or <strong>Connect Gmail</strong> on an existing unconnected mailbox). NGX records the mailbox and redirects you to Google consent.</li>\n<li>Sign in as the dedicated Gmail account. If you use more than one Google account, do this in a fresh Incognito / private window (see <em>Before you start</em>) so Google does not sign you in as the wrong one.</li>\n<li>Because the app is in Testing, Google shows a <strong>&quot;Google hasn&#39;t verified this app&quot;</strong> warning. This is expected. Select <strong>Advanced</strong>, then <strong>Go to NGX Ramblers Inbox (unsafe)</strong>, and approve.</li>\n</ol>\n<p><img src=\"https://ngx-ramblers.org.uk/api/aws/s3/site-content/f626acaf-6a81-4ded-9dd7-395562e768cb.png\" alt=\"\"></p>\n<p><em>Because the app is in Testing, Google shows a “Google hasn’t verified this app” warning; as a listed test user, continue past it.</em></p>\n<p><img src=\"https://ngx-ramblers.org.uk/api/aws/s3/site-content/2bd2181d-3781-4c48-a662-559279fa60ca.png\" alt=\"\"></p>\n<p><em>Approve the gmail.modify access request to return to NGX, where an encrypted refresh token is stored.</em></p>\n<ol start=\"4\">\n<li>Google returns you to NGX. The mailbox flips from &quot;New Gmail inbox&quot; to the connected email address, and an encrypted refresh token is stored.</li>\n</ol>\n<p>Assigning further committee roles to an already connected mailbox does not require another consent flow.</p>\n<p><strong>Before you rely on this mailbox, publish the app to production.</strong> The refresh token you have just stored expires after seven days while the app is in Testing. The <em>Keep the connection alive</em> section below covers this — it is the step most people miss.</p>\n<h3>Map roles and configure forwarding</h3>\n<p>Still in the <strong>Gmail Inbox</strong> section (<strong>Mail Settings → Inbox</strong>):</p>\n<ul>\n<li>Set the <strong>Committee mailbox access</strong> policy per connected inbox. <strong>All committee role mailboxes</strong> lets any committee user view and reply to roles mapped to that inbox. <strong>Assigned roles only</strong> restricts each role to the committee members assigned to it.</li>\n<li>Use <strong>Role mailbox assignments</strong> to point committee role addresses at the relevant Gmail inbox.</li>\n<li>Select <strong>Configure forwarding</strong> on a connected inbox to create or update the Cloudflare Email Routing rules. Cloudflare sends a verification email to the Gmail destination; confirm it in Gmail, then select <strong>Configure forwarding</strong> again to apply the rules.</li>\n</ul>\n<p><img src=\"https://ngx-ramblers.org.uk/api/aws/s3/site-content/3b6e6232-f508-4a42-add9-2339562c8d9c.png\" alt=\"\"></p>\n<p><em>After confirming the Cloudflare verification email in the Gmail account, routing to the mailbox is verified.</em></p>\n<h3>Delivery: pull or push</h3>\n<p>Each connected mailbox has a <strong>Delivery</strong> setting on the <strong>Connected Gmail accounts</strong> step:</p>\n<ul>\n<li><strong>Pull</strong> (default) polls Gmail every 30 seconds. No extra setup - this is the lowest-friction option and all you need for a first test.</li>\n<li><strong>Push</strong> uses Gmail&#39;s real-time notifications via a Google Cloud Pub/Sub topic. NGX provisions this for you in one click rather than by hand:<ol>\n<li>Add the <code>https://www.googleapis.com/auth/cloud-platform</code> scope to your OAuth client, on the same <strong><a href=\"https://console.cloud.google.com/auth/scopes\">Data Access</a></strong> screen where you added <code>gmail.modify</code>. The one-click setup signs in with this scope.</li>\n<li>On the <strong>Pub/Sub setup</strong> step, enter a Google Cloud project ID you own and a topic name (default <code>ngx-inbox-events</code>), then select <strong>Run Google Cloud setup</strong>. After Google&#39;s consent screen, NGX enables the Gmail and Pub/Sub APIs, creates the topic, grants <code>gmail-api-push@system.gserviceaccount.com</code> the Pub/Sub Publisher role, and creates a push subscription pointed at NGX&#39;s push-receiver URL - no manual Cloud console steps.</li>\n<li>Back on the mailbox, set <strong>Delivery</strong> to <strong>Push</strong> and select <strong>Apply push</strong>. Switching back to <strong>Pull</strong> stops the watch and resumes polling.</li>\n</ol>\n</li>\n</ul>\n<p>The push registration expires after seven days; a daily job renews it and catches up on anything missed, so push degrades safely even if a notification is dropped.</p>\n<h2>Keep the connection alive: publish the app to production</h2>\n<p>While the app&#39;s <strong>Publishing status</strong> is <strong>Testing</strong>, Google expires the stored refresh token <strong>after seven days</strong>, used or not. When that happens the mailbox stops importing, its status shows a revoked token, and the error is <code>invalid_grant</code>. This is the most common reason a working inbox goes quiet about a week after it was first connected, and it is nothing you did wrong — it is Google&#39;s policy for an app that is still in Testing.</p>\n<p>The fix is to take the app out of Testing once you have confirmed the mailbox connects and imports mail:</p>\n<ol>\n<li>Open <strong><a href=\"https://console.cloud.google.com/auth/audience\">Audience</a></strong> (sign in as the account that owns the project, in a private window if you juggle several Google accounts).</li>\n<li>Under <strong>Publishing status</strong>, select <strong>Publish app</strong> and confirm the dialog.</li>\n<li>The status changes to <strong>In production</strong>, and refresh tokens stop expiring. Reconnect the mailbox once more to replace the short-lived seven-day token with a durable one.</li>\n</ol>\n<p>What you do <em>not</em> need to do:</p>\n<ul>\n<li><strong>You do not need to complete verification.</strong> An unverified app in production still issues working, non-expiring tokens for your own mailbox. The &quot;Google hasn&#39;t verified this app&quot; warning still appears at consent, and you click past it exactly as before. Verification only matters if you publish a logo or open the app to the wider public.</li>\n<li><strong>Do not upload an app logo</strong> on the <strong>Branding</strong> screen. A logo forces the app into mandatory verification. For a role mailbox you want it published but unverified, so leave the logo blank.</li>\n</ul>\n<p>This is a different seven-day clock from the push watch described under <em>Delivery: pull or push</em>. Publishing the app fixes the <strong>token</strong>; the push <strong>watch</strong> renews itself automatically. A mailbox you intend to keep running needs both, which in practice means it needs the app published to production.</p>\n<h2>Troubleshooting</h2>\n<p><strong>Error 400: redirect_uri_mismatch</strong> on the Google sign-in screen. The redirect URI NGX sent does not exactly match any Authorised redirect URI on the OAuth client. The two values must be identical down to the scheme (<code>http</code> vs <code>https</code>), host, port, path, and the absence of a trailing slash. Compare the <strong>OAuth Redirect URI</strong> saved in NGX (<strong>Mail Settings → Inbox</strong>, Gmail Inbox section) against the <strong>Authorised redirect URIs</strong> on the client in <a href=\"https://console.cloud.google.com/auth/clients\">Google Cloud → Clients</a>, fix whichever is wrong, save, and retry. The failed Google URL contains a <code>redirect_uri=</code> parameter showing exactly what NGX sent.</p>\n<p><strong>&quot;Google Inbox OAuth client is not configured.&quot;</strong> One or more of Client ID, Client Secret or Redirect URI is blank in the <strong>Gmail Inbox</strong> section (<strong>Mail Settings → Inbox</strong>). Fill all three and save.</p>\n<p><strong>&quot;Access blocked&quot; / the account is refused at consent.</strong> The Gmail account you are signing in as is not listed as a test user while the app is in Testing. Add it under <a href=\"https://console.cloud.google.com/auth/audience\">Google Auth Platform → Audience → Test users</a>.</p>\n<p><img src=\"https://ngx-ramblers.org.uk/api/aws/s3/site-content/f10e7b09-20fa-494a-9825-a3098be61fee.png\" alt=\"\"></p>\n<p><em>“Access blocked … Error 403: access_denied” means the account signing in is not listed as a Test user while the app is in Testing.</em></p>\n<p><strong>Google did not return a refresh token.</strong> This happens if the account previously authorised the app. Remove the app&#39;s access in the Google account&#39;s security settings, then retry the consent flow.</p>\n<p><strong>Replies stop arriving.</strong> The usual cause is the seven-day Testing-mode token expiry described under <em>Keep the connection alive</em>: while the app is in <strong>Testing</strong>, Google revokes the refresh token about a week after it was issued, and the mailbox status shows a revoked token with the error <code>invalid_grant</code>. Publish the app to production so this stops recurring, then reconnect the mailbox to mint a fresh, durable token. (A token can also be revoked if the Gmail password changes or Google tightens a policy review.) A daily health check pings each connected mailbox, and when it finds a revoked token it now sends a push notification to the inbox so you are not left guessing. Re-scanning the general mailbox no longer clears existing threads when the token is broken — it reports the error and leaves your mail in place — and reconnecting re-imports anything missed and restarts push delivery straight away.</p>\n<p><strong>Recovery steps:</strong></p>\n<ol>\n<li>If the app&#39;s publishing status is still <strong>Testing</strong>, publish it to production first (see <em>Keep the connection alive</em>), otherwise the replacement token will expire again after seven days.</li>\n<li>In NGX, open the <strong>Gmail Inbox</strong> section (<strong>Mail Settings → Inbox</strong>) and find the affected mailbox under <strong>Connected Gmail accounts</strong>.</li>\n<li>Select <strong>Reconnect</strong> and complete Google consent as the dedicated Gmail account. If you are signed into several Google accounts, do this in a fresh Incognito / private window so Google does not pick the wrong one.</li>\n<li>The mailbox returns to connected, the backlog re-imports, and push delivery restarts automatically.</li>\n</ol>\n"}