Connect Zoho Mail to let an Agent list inbox messages, filter them by date, and read individual messages.
Agent Barn stores the OAuth client secret and refresh token as encrypted Agent Secrets. The Agent accesses Zoho Mail through the built-in Zoho Mail Skill and the aai-cli email command group. This integration is read-only.
Supported Zoho services
Zoho Mail
Supported — read-only access.
Supported: listing inbox messages, filtering listed messages by received date, reading an individual message by its Zoho message ID, and returning decoded subjects, addresses, dates, and bodies.
Not supported: sending or replying to email, moving, archiving, labeling, or deleting messages, marking messages read or unread, managing folders, and accessing administrative Zoho Mail settings.
Zoho Calendar
Not currently configurable — not available in the Agent Barn integration selector.
Although zoho_calendar exists as an internal provider model, it is disabled in the UI, and does not have a mounted Agent Skill or a verified Agent command surface.
Do not configure a Zoho Calendar credential through the API expecting it to work as a supported Agent integration.
What you will configure
- Zoho Mail account
- OAuth Self Client
- Authorization code
- Refresh token
- Encrypted Agent Secret
- Zoho Mail Skill
Zoho Mail account
│
▼
Zoho OAuth Self Client
│
├── Client ID
├── Client secret
└── Read-only scopes
│
▼
Authorization code
│
▼
Access + refresh tokens
│
├── Access token used temporarily
│ to find the Account ID
│
└── Refresh token saved in Agent Barn
│
▼
Encrypted Agent Secret
│
▼
Zoho Mail Skill + aai-cliAt the end of this guide, the Agent will have:
- A
zoho_mailcredential - The built-in Zoho Mail Skill
- A generated
zoho-mail-restprofile - Read-only access to the selected Zoho Mail account
- Automatic access-token refresh during runtime requests
Before you begin
You need:
- An Agent Barn Organization
- An existing Agent, or permission to hire one
- Permission to update the Agent and manage its Secrets
- A Zoho Mail account
- Access to the Zoho API Console for that account
- A terminal with
curl - Permission to authorize read access to the intended mailbox
Use a dedicated mailbox when the Agent should not inherit a person’s complete inbox.
Official references:
Check your Zoho data center
The current Agent Barn profile does not include a Zoho data-center field. Its runtime defaults are:
OAuth server: https://accounts.zoho.com
Mail API: https://mail.zoho.comThis is the US/global .com Zoho data center. After signing in to Zoho Mail, check the domain in the browser.
| Browser domain | Data center | Current Agent Barn support |
|---|---|---|
mail.zoho.com | US/global | Supported |
mail.zoho.eu | Europe | Not currently configurable |
mail.zoho.in | India | Not currently configurable |
mail.zoho.com.au | Australia | Not currently configurable |
mail.zoho.jp | Japan | Not currently configurable |
mail.zohocloud.ca | Canada | Not currently configurable |
mail.zoho.com.cn | China | Not currently configurable |
mail.zoho.ae | United Arab Emirates | Not currently configurable |
mail.zoho.sa | Saudi Arabia | Not currently configurable |
Plan OAuth scopes
Request these two read-only scopes.
| Scope | Purpose | Required |
|---|---|---|
ZohoMail.accounts.READ | Lists the user’s Zoho Mail accounts and identifies the account ID | Yes |
ZohoMail.messages.READ | Lists and reads messages | Yes |
Enter the scopes as one comma-separated value:
ZohoMail.accounts.READ,ZohoMail.messages.READDo not request ALL, CREATE, UPDATE, or DELETE scopes for this integration. The current Agent Skill is read-only, so broader scopes do not add supported Agent capabilities.
Create a Self Client
- Sign in to the Zoho account that owns the mailbox.
- Open the Zoho API Console.
- Select Get Started or Add Client.
- Select Self Client.
- Select Create Now.
- Confirm creation.
- Open the Client Secret tab.
- Copy the Client ID.
- Copy the Client Secret into a secure temporary location.
The values resemble:
Client ID
1000.EXAMPLECLIENTID
Client Secret
REDACTEDA Self Client is appropriate because this is a backend automation integration for a mailbox you control. Agent Barn does not currently provide a user-facing Zoho OAuth callback flow.
Generate an authorization code
- Open the Self Client in the Zoho API Console.
- Select Generate Code.
- Enter the two read-only scopes.
- Choose a short duration, such as 10 minutes.
- Enter a description such as
Agent Barn read-only Zoho Mail integration. - Select Create.
- Review and approve the requested access.
- Copy the authorization code immediately.
ZohoMail.accounts.READ,ZohoMail.messages.READExchange the code for tokens
Use the authorization code, client ID, and client secret to request an access token and refresh token.
To avoid putting secrets directly into shell history, collect them through prompts:
read -r "ZOHO_CLIENT_ID?Zoho client ID: "
read -s "ZOHO_CLIENT_SECRET?Zoho client secret: "
echo
read -s "ZOHO_AUTH_CODE?Zoho authorization code: "
echoExchange the authorization code:
curl --silent --show-error \
--request POST \
"https://accounts.zoho.com/oauth/v2/token" \
--data-urlencode "code=${ZOHO_AUTH_CODE}" \
--data-urlencode "grant_type=authorization_code" \
--data-urlencode "client_id=${ZOHO_CLIENT_ID}" \
--data-urlencode "client_secret=${ZOHO_CLIENT_SECRET}" \
--data-urlencode "redirect_uri=https://api-console.zoho.com/callback"A successful response resembles:
{
"access_token": "REDACTED",
"refresh_token": "REDACTED",
"api_domain": "https://www.zohoapis.com",
"token_type": "Bearer",
"expires_in": 3600
}Save these values:
client_id
client_secret
refresh_tokenKeep the temporary access_token long enough to retrieve the mailbox’s account ID.
Find the Zoho Mail account ID
Zoho Mail API requests use a numeric account ID rather than the email address alone.
Store the temporary access token without placing it directly into the next command:
read -s "ZOHO_ACCESS_TOKEN?Temporary Zoho access token: "
echoList the accounts available to the authorized user:
curl --silent --show-error \
"https://mail.zoho.com/api/accounts" \
--header "Accept: application/json" \
--header "Authorization: Zoho-oauthtoken ${ZOHO_ACCESS_TOKEN}"The response contains an account collection. Find the entry matching the mailbox email and copy its accountId. A shortened example looks like:
{
"status": {
"code": 200,
"description": "success"
},
"data": [
{
"accountId": "56218000000008002",
"primaryEmailAddress": "[email protected]"
}
]
}Record:
Email: [email protected]
Account ID: 56218000000008002Then remove the temporary access token from the shell with unset ZOHO_ACCESS_TOKEN.
The account ID is not the Zoho Organization ID, User ID, or folder ID. Use the value named accountId.
Connect Zoho Mail
- In Agent Barn, open Agents.
- Select the Agent that needs mailbox access.
- Open the Agent’s Configuration.
- Select Keys & integrations.
- Select Edit.
- Under Integration credentials, add Zoho Mail.
- Select Manual credential.
- Complete all Zoho Mail fields.
- Apply the configuration.
| Agent Barn field | Required | Value |
|---|---|---|
| Yes | The authorized Zoho Mail address | |
| Account ID | Yes | The numeric accountId returned by the Accounts API |
| Client ID | Yes | The OAuth Self Client ID |
| Client secret | Yes | The OAuth Self Client secret |
| Refresh token | Yes | The refresh token returned by the authorization-code exchange |
Example:
Email
[email protected]
Account ID
56218000000008002
Client ID
1000.EXAMPLECLIENTID
Client secret
••••••••••••••••
Refresh token
••••••••••••••••If the Agent is running, use the website’s restart-aware apply flow. The runtime profile becomes available after restart.
Assign the Zoho Mail Skill
The credential supplies authentication. The Skill supplies the supported command instructions.
- Open the Agent’s Skills configuration.
- Select Edit.
- Add the built-in Zoho Mail Skill.
- Apply the change.
- Restart the Agent if prompted.
The mounted Skill is available at:
./skills/aai-cli/zoho_mail_skill.mdThe supported runtime interface is aai-cli email, and every Zoho Mail command must include --profile zoho-mail-rest.
Agent Barn requires a zoho_mail credential while the Zoho Mail Skill is assigned.
Verify Agent access
Zoho Mail does not currently have an Agent Barn live credential validator. Verify the integration by running a real read operation after the Agent starts.
List three inbox messages:
aai-cli email messages list \
--limit 3 \
--profile zoho-mail-restA successful response resembles:
{
"data": [
{
"folderId": "56218000000008014",
"fromAddress": "[email protected]",
"messageId": "1781850728498141700",
"receivedTime": "1781850728475",
"subject": "Example notification",
"summary": "A short preview of the message..."
}
],
"status": {
"code": 200,
"description": "success"
}
}Use a returned messageId to read one message:
aai-cli email messages get 1781850728498141700 \
--profile zoho-mail-restA successful response resembles:
{
"id": "1781850728498141700",
"subject": "Example notification",
"from": "Notifications <[email protected]>",
"to": "Agent <[email protected]>",
"date": "Fri, 19 Jun 2026 06:32:07 +0000",
"body": "The decoded message body.",
"body_type": "text"
}Filter listed messages by date:
aai-cli email messages list \
--limit 20 \
--received-after 2026-08-01 \
--received-before 2026-09-01 \
--profile zoho-mail-restThe lower date is inclusive, and the upper date is exclusive.
Date filtering is performed after fetching up to 200 messages. A response containing "truncated": true means more possible matches exist beyond the fetched page.
Validation behavior
Live validation is not currently implemented for zoho_mail.
For an Agent-owned credential, the integration validation endpoint is not a supported connectivity test. It currently returns an error equivalent to:
{
"detail": "No validator available for zoho_mail"
}Shared Credential validation reports that live validation is unsupported.
This does not, by itself, mean the saved OAuth values are invalid. The authoritative verification is a successful runtime command.
POST /api/v1/organizations/{organization_id}/agents/{agent_id}/integrations/zoho_mail/validateaai-cli email messages list --limit 1 --profile zoho-mail-restRuntime behavior
When the Agent starts, Agent Barn:
- Decrypts the Zoho Mail credential.
- Stores the client secret and refresh token in the encrypted
aai-clisecret store. - Generates the
zoho-mail-restprofile. - Mounts the built-in Zoho Mail Skill.
- Adds the configured integration to the Agent’s tool context.
The generated profile resembles:
[profiles.zoho-mail-rest]
provider = "zoho"
auth_type = "zoho_oauth"
email = "[email protected]"
account_id = "56218000000008002"
client_id = "1000.EXAMPLECLIENTID"
client_secret_secret = "zoho.client_secret"
refresh_token_secret = "zoho.mail_refresh_token"The actual secret values are not embedded in the profile. The secret references are zoho.client_secret and zoho.mail_refresh_token.
For each request, aai-cli:
- Reads the client ID, client secret, and refresh token.
- Requests a fresh short-lived access token from Zoho.
- Calls the Zoho Mail API using that access token.
- Returns successful output as JSON.
- Returns failures as structured JSON on standard error.
Encrypted refresh token
│
▼
aai-cli request
│
▼
accounts.zoho.com OAuth token endpoint
│
▼
Short-lived access token
│
▼
mail.zoho.com APIAgent Barn does not store a temporary access token. No cron job or manual access-token refresh is required, and credential changes take effect after the Agent restarts.
Use a Shared Credential
Zoho Mail supports Organization-owned Shared Credentials. Use one when:
- Multiple Agents should read the same mailbox
- An Organization administrator should own OAuth rotation
- Agent operators should not handle the client secret or refresh token
- The same Zoho account ID applies to each attached Agent
To attach one:
- Create or locate the Zoho Mail Shared Credential in the Organization.
- Open the Agent’s Keys & integrations configuration.
- Add Zoho Mail.
- Switch from Manual credential to Shared Credential.
- Select the intended credential.
- Apply the change.
- Restart the Agent if prompted.
- Run a real
aai-cli emailcommand.
An Agent can use either a manual Zoho Mail credential or a Shared Zoho Mail Credential, not both simultaneously.
Live validation remains unsupported for the Shared Credential. Verify it from an attached Agent after restart.
Continue to Use shared credentials for the complete ownership model.
Rotate or remove the credential
Rotate the refresh token
- Open the existing Self Client in the Zoho API Console.
- Generate a new authorization code with both read-only scopes.
- Exchange the new code for tokens.
- Confirm that the response includes a new refresh token.
- Replace the complete Zoho Mail credential in Agent Barn.
- Restart the Agent.
- Run
messages list. - Revoke the old refresh token after the new credential works.
Rotate the client secret
If Zoho provides a new client secret:
- Record the new client ID or secret.
- Generate a new authorization code for that client.
- Exchange it for a new refresh token.
- Replace the Agent Barn credential as one unit.
- Restart and verify the Agent.
- Revoke the old OAuth credentials.
A refresh token is associated with the client that issued it. Do not combine a refresh token from one Self Client with another client’s ID or secret.
Remove the credential
Before removing Zoho Mail:
- Remove or replace any assigned Skill that requires
zoho_mail. - Stop the Agent, or use the website’s restart-aware apply flow.
- Open Keys & integrations.
- Mark the Zoho Mail credential for removal.
- Apply the change.
- Restart and verify the Agent.
Agent Barn blocks removal while an assigned Skill still requires the zoho_mail provider.
API reference
Add or replace a manual Zoho Mail credential
The Agent must be stopped when using the raw update endpoint.
PATCH /api/v1/organizations/{organization_id}/agents/{agent_id}
Content-Type: application/json{
"secrets": [
{
"provider": "zoho_mail",
"content": {
"email": "[email protected]",
"account_id": "56218000000008002",
"client_id": "1000.EXAMPLECLIENTID",
"client_secret": "REDACTED",
"refresh_token": "REDACTED"
}
}
]
}Attach a Shared Credential
{
"shared_credentials": [
{
"shared_credential_id": "00000000-0000-0000-0000-000000000000"
}
]
}Remove the credential
{
"removed_secret_providers": [
"zoho_mail"
]
}Credential operations require access to the Agent and the relevant update and secret-management permissions, including agent.secret.manage.
Troubleshooting
The token exchange does not return a refresh token
Wrong grant, or an expired code
Confirm that you:
- Used a Self Client authorization code
- Used the authorization-code grant
- Did not use the client-credentials grant
- Exchanged the code before it expired
- Used the client ID and secret belonging to the same Self Client
- Used the
.comAPI Console and Accounts endpoint - Requested the code for the correct Zoho account
Generate a new authorization code and exchange it immediately.
Zoho reports an invalid code
Codes are short-lived and single-use
Generate another code in the Self Client and exchange it before its selected duration expires.
Zoho reports an invalid client
Client values or data center mismatch
Check that:
- The client ID is complete
- The client secret is complete
- Both values belong to the same Self Client
- The token request uses
https://accounts.zoho.com - The Self Client was created in the US/global data center
The Accounts API returns a scope error
Both scopes are required
Generate a new authorization code containing both scopes:
ZohoMail.accounts.READ,ZohoMail.messages.READA token containing only the message scope cannot reliably discover the account ID.
The Agent reports an authentication error
Check the stored values and restart
Check that:
- The refresh token was entered, not the temporary access token
- The client ID, client secret, and refresh token belong to the same Self Client
- The refresh token has not been revoked
- The mailbox uses the
.comZoho data center - The Agent was restarted after the credential changed
The Agent reports an invalid account ID
Use the accountId value
Call GET https://mail.zoho.com/api/accounts with a temporary access token, and copy the accountId matching the configured mailbox.
Do not use the Organization ID, Zoho User ID, folder ID, or message ID.
The mailbox is hosted at a regional Zoho domain
Regional endpoints are not configurable
The current Agent Barn credential does not expose regional OAuth or Mail API endpoints. The generated runtime defaults to https://accounts.zoho.com and https://mail.zoho.com.
Regional Zoho Mail accounts are not currently supported through this configuration page. Regional support requires product changes to store and generate the correct Accounts and Mail API base URLs.
Listing messages works but expected messages are missing
Inbox listing, not mailbox search
The current command lists inbox messages rather than providing a complete mailbox-wide search. Also note:
--limitrestricts returned results- Date filtering fetches at most 200 messages before filtering
truncated: truemeans additional matches may exist- Messages in another folder may not appear
Message bodies contain simplified formatting
HTML is stripped to text
messages get returns decoded plain text when available. If only HTML is available, the command strips tags and reports "body_type": "html".
Validate reports that no validator is available
Expected for this provider
This is expected for the current zoho_mail integration. Restart the Agent and run:
aai-cli email messages list --limit 1 --profile zoho-mail-rest The credential cannot be removed
A Skill still requires it
A remaining assigned Skill requires Zoho Mail. Remove the Zoho Mail Skill before removing the credential.
Updated credentials are not being used
Artifacts are produced at startup
Restart the Agent. Encrypted runtime Secrets, the zoho-mail-rest profile, mounted Skills, and generated tool context are created during Agent startup.
Security practices
- Use a dedicated mailbox when possible
- Request only
ZohoMail.accounts.READandZohoMail.messages.READ - Do not request write or administrative scopes
- Protect both the client secret and refresh token
- Never store an access token, refresh token, authorization code, or client secret in source control
- Do not place secrets directly in shell commands saved to history
- Do not send OAuth values through Agent conversations
- Prefer Shared Credentials when administrators should own rotation
- Use separate OAuth clients for separate security boundaries
- Restart and test after every credential rotation
- Revoke unused refresh tokens
- Replace the Self Client immediately if its client secret is exposed
- Treat mailbox content as sensitive data when reviewing Agent logs and outputs