Connecting mailboxes
How connecting a mailbox works
Campbooks reads and sends Gmail and Zoho Mail through the provider's own API. Any other mailbox (Yahoo, AOL, iCloud, Fastmail, GMX, WEB.DE, Yandex, a custom domain) connects over IMAP and SMTP with an app password: see IMAP mailboxes. Outlook and Microsoft 365 are coming.
For Gmail and Zoho there is nothing extra to register. The OAuth client you set up for Sign-in is the same client that connects the mailbox. It uses the same redirect URI and the same client ID and secret file. A provider offers mail connection once its client is configured, and not before.
- Add a mailbox. In the app, open Settings, then Mailboxes, and choose Add a mailbox. It asks for the address first. A Gmail or Zoho address goes to the provider's consent screen, which asks for access to the mail; any other address gets the app-password step. Gmail and Zoho are offered only once your instance has set up their client. Steps for members: Connect your mailbox.
- Also sign in. The connect step has a box, "Also use this account to sign in", ticked by default. Untick it for a shared mailbox such as
support@. It is then connected but never becomes a way to sign in. - Who can see it. A connection belongs to the workspace and records who connected it. Owners and admins see every mailbox of the workspace.
- Credentials. The grant Campbooks gets from the provider, or an IMAP mailbox's password, is sealed with the instance secret key. Lose the key and the connections cannot be opened, so each person would have to connect again. See The instance secret key.
- Disconnect. Disconnecting stops the sync and revokes the grant at the provider. You choose whether the mail already in Campbooks is deleted (the default) or kept as read-only history. The mail at Gmail or Zoho is never touched. Leaving the workspace, or deleting the workspace, also revokes the grants.
- Health. Each mailbox shows one of four states: Syncing, Needs the member to reconnect, Slowed down by the provider, or Failing. A mailbox that needs a reconnect has a Reconnect button for the person who connected it.
Connecting mail needs the built-in sign-in. If you set CAMPBOOKS_AUTH__ISSUER to an outside issuer, mailbox connection is off.
Gmail
This works for personal Gmail and for Google Workspace accounts.
What Campbooks asks Google for
Campbooks asks for openid, email and profile to identify the account, and one Gmail scope:
https://www.googleapis.com/auth/gmail.modify
That scope reads mail, changes labels and sends. It cannot delete mail permanently.
Set up the Google Cloud project
-
In the Google Cloud console, create a project, or choose the one you use for sign-in.
-
Open APIs & Services, then Library, and enable the Gmail API for that project. Without it, Google refuses every mail request.
-
Open OAuth consent screen (in newer consoles, Google Auth Platform). Choose the user type:
- External for personal Gmail accounts, or for Workspace users outside your organization.
- Internal if everyone who will connect is in your own Google Workspace organization. An internal app needs no verification.
-
Add the scopes
openid,email,profileandhttps://www.googleapis.com/auth/gmail.modify. -
Set the publishing status. See the next section.
-
Open Credentials, then Create credentials, then OAuth client ID. Choose Web application and add this authorized redirect URI:
https://campbooks.example.com/auth/callback/googleUse your own
CAMPBOOKS_PUBLIC_URL. The URI must match exactly, with no trailing slash. -
Put the client ID in
.envand the client secret indeploy/secrets/google-client-secret, then rundocker compose up -d. The file permissions and the.envlines are the ones in Sign in with Google, Microsoft or Zoho:CAMPBOOKS_GOOGLE__CLIENT_ID=your-client-idCAMPBOOKS_GOOGLE__CLIENT_SECRET_FILE=/run/secrets/campbooks/google-client-secret
Testing, publishing and verification
Google treats gmail.modify as a restricted scope. This decides who can connect:
- Testing. Only the test users you list can connect, up to 100. Refresh tokens last 7 days, so every connection stops after a week and needs a reconnect. Use Testing only to try things out.
- In production, unverified. Anyone can connect, but they see Google's "Google hasn't verified this app" screen and must choose Advanced, then continue. Refresh tokens do not expire after 7 days. For a personal instance with a few users this is usually fine. Google also caps unverified apps at 100 users in total.
- In production, verified. Google removes the warning after it reviews the app. For a restricted scope, Google requires a security assessment. This is rarely worth it for a self-hosted instance.
For a lasting setup, publish the app (Publish app on the consent screen) and accept the warning.
How it syncs
Campbooks polls Gmail. There is no push setup and nothing to register with Google for it. After a sync that found changes, the next one runs within a minute. When nothing changes, the interval backs off, up to four hours. A new connection reads back 90 days by default. You can change these in Tuning.
Zoho Mail
What Campbooks asks Zoho for
Campbooks asks for openid, email and profile, and four Zoho Mail scopes:
| Scope | Used for |
|---|---|
ZohoMail.accounts.READ | Listing the mail accounts under the login. |
ZohoMail.folders.READ | Reading the folders. |
ZohoMail.messages.ALL | Reading, changing and sending messages. |
ZohoMail.tags.ALL | Reading and making labels, for streams. |
Zoho's consent screen is all or nothing. If any scope is missing from the grant, Campbooks refuses it and asks you to connect again.
Set up the Zoho app
-
Open the Zoho API console for your region, for example
https://api-console.zoho.eufor the EU. Add a client of type Server-based Applications. -
Turn on Multi-DC, so one client works for every Zoho data centre. Without it, the client works only in the data centre where you made it.
-
Add the redirect URI:
https://campbooks.example.com/auth/callback/zoho -
A server-based Zoho app takes its scopes with each request, so there is nothing more to register for them.
-
Put the client ID in
.envand the client secret indeploy/secrets/zoho-client-secret, then rundocker compose up -d:CAMPBOOKS_ZOHO__CLIENT_ID=your-client-idCAMPBOOKS_ZOHO__CLIENT_SECRET_FILE=/run/secrets/campbooks/zoho-client-secret
Data centres
Zoho keeps each account in one data centre, and Campbooks reads its mail from there. These accounts servers are accepted:
| Region | Accounts server |
|---|---|
| United States | https://accounts.zoho.com (default) |
| Europe | https://accounts.zoho.eu |
| India | https://accounts.zoho.in |
| Australia | https://accounts.zoho.com.au |
| Japan | https://accounts.zoho.jp |
| Canada | https://accounts.zoho.ca |
| Saudi Arabia | https://accounts.zoho.sa |
| United Kingdom | https://accounts.zoho.uk |
With Multi-DC on, leave CAMPBOOKS_ZOHO__ACCOUNTS_SERVER unset. Without Multi-DC, set it to the accounts server of the data centre where you registered the client:
CAMPBOOKS_ZOHO__ACCOUNTS_SERVER=https://accounts.zoho.eu
Several mail accounts under one login
One Zoho login can hold several mail accounts. Each mail account becomes its own inbox in Campbooks. A person can connect more than one Zoho login.
When someone signs up with Zoho, Zoho asks a second time for access to the mail, and only if the account is new. Signing in again never asks.
Reconnect once for labels
Zoho connections made before the labels scope was added keep syncing, but without labels or streams. To get them, reconnect the mailbox once from Settings, then Mailboxes. Campbooks then adds Campbooks/<Stream> labels in Zoho for the streams Zoho has no place for.
How it syncs
Campbooks polls Zoho, because Zoho has no push. Zoho has no change log either, so Campbooks also re-reads each mailbox's whole window every 6 hours by default. It keeps to 60 requests a minute for each Zoho login. Change these in Tuning.
Tuning
All of these are optional, and the defaults are fine for most instances. Add them to .env and run docker compose up -d. They are also listed in Configuration.
| Variable | Default | What it does |
|---|---|---|
CAMPBOOKS_CONNECTORS__GMAIL__BACKFILL_DAYS | 90 | How far back a new Gmail connection reads. 1 to 3650. |
CAMPBOOKS_CONNECTORS__POLL__MIN_SECONDS | 60 | Interval after a sync that found changes. |
CAMPBOOKS_CONNECTORS__POLL__MAX_SECONDS | 14400 | Longest interval for an idle mailbox. |
CAMPBOOKS_CONNECTORS__ZOHO__BACKFILL_DAYS | 90 | How far back a new Zoho mailbox reads. 1 to 3650. |
CAMPBOOKS_CONNECTORS__ZOHO__REQUESTS_PER_MINUTE | 60 | Requests each Zoho login may make per minute. |
CAMPBOOKS_CONNECTORS__ZOHO__SWEEP_MINUTES | 360 | Minutes between full re-reads of a Zoho mailbox's window. |
The size limits, the Google quota budget and the failure thresholds are in Configuration.
Troubleshooting
| What you see | Cause and fix |
|---|---|
Google: Error 400: redirect_uri_mismatch | The redirect URI in the Google client is not exactly ${CAMPBOOKS_PUBLIC_URL}/auth/callback/google. Check https://, the host, and that there is no trailing slash. |
Google: access_denied, or "This app is blocked" or "has not completed the Google verification process" | The app is in Testing and the person is not a listed test user. Add them under the consent screen's test users, or publish the app. |
Google: sync fails with 403 accessNotConfigured, or "Gmail API has not been used in project" | The Gmail API is not enabled in the project that owns the client. Enable it under APIs & Services, then Library, and wait a few minutes. |
| Google: connections stop after about 7 days | The app is in Testing, which limits refresh tokens to 7 days. Publish the app, then reconnect each mailbox. |
Zoho: invalid_client | The client was registered in a different data centre. Turn on Multi-DC, or set CAMPBOOKS_ZOHO__ACCOUNTS_SERVER to the accounts server of the data centre where you made the client. |
| Zoho: a redirect error on the consent screen | The redirect URI in the Zoho client is not exactly ${CAMPBOOKS_PUBLIC_URL}/auth/callback/zoho. |
| "Campbooks was not given access to what you chose" | The person left out a permission on the consent screen. Connect again and allow all of it. |
| "Needs the member to reconnect" on a mailbox | The provider revoked or expired the grant. The person who connected it chooses Reconnect (or presses R) in Settings, then Mailboxes. |
| "Campbooks does not know the Zoho data centre of this account" | The account is in a data centre outside the list above. |
| The provider is not offered under Connect | Its client ID or secret is not set, or the server was not restarted. Check docker compose logs server. |
Other mailboxes
Any other mailbox connects over IMAP and SMTP with an app password. It is on by default and needs only the instance secret key. See IMAP mailboxes. Outlook and Microsoft 365 mail are coming.