Zoho Mail
Zoho Mail API integration with managed OAuth. Send, receive, and manage emails, folders, and labels. Use this skill when users want to send emails, read mess...
Zoho Mail API integration with managed OAuth. Send, receive, and manage emails, folders, and labels. Use this skill when users want to send emails, read mess...
Real data. Real impact.
Emerging
Developers
Per week
Open source
Skills give you superpowers. Install in 30 seconds.
Access the Zoho Mail API with managed OAuth authentication. Send, receive, search, and manage emails with full folder and label management.
# List all accounts python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/zoho-mail/api/accounts') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
https://gateway.maton.ai/zoho-mail/{native-api-path}
Replace
{native-api-path} with the actual Zoho Mail API endpoint path. The gateway proxies requests to mail.zoho.com and automatically injects your OAuth token.
All requests require the Maton API key in the Authorization header:
Authorization: Bearer $MATON_API_KEY
Environment Variable: Set your API key as
MATON_API_KEY:
export MATON_API_KEY="YOUR_API_KEY"
Manage your Zoho Mail OAuth connections at
https://ctrl.maton.ai.
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections?app=zoho-mail&status=ACTIVE') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
python <<'EOF' import urllib.request, os, json data = json.dumps({'app': 'zoho-mail'}).encode() req = urllib.request.Request('https://ctrl.maton.ai/connections', data=data, method='POST') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Content-Type', 'application/json') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
Response:
{ "connection": { "connection_id": "21fd90f9-5935-43cd-b6c8-bde9d915ca80", "status": "ACTIVE", "creation_time": "2025-12-08T07:20:53.488460Z", "last_updated_time": "2026-01-31T20:03:32.593153Z", "url": "https://connect.maton.ai/?session_token=...", "app": "zoho-mail", "metadata": {} } }
Open the returned
url in a browser to complete OAuth authorization.
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}', method='DELETE') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
If you have multiple Zoho Mail connections, specify which one to use with the
Maton-Connection header:
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/zoho-mail/api/accounts') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Maton-Connection', '21fd90f9-5935-43cd-b6c8-bde9d915ca80') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
If omitted, the gateway uses the default (oldest) active connection.
Retrieve all mail accounts for the authenticated user.
GET /zoho-mail/api/accounts
Example:
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/zoho-mail/api/accounts') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
GET /zoho-mail/api/accounts/{accountId}
GET /zoho-mail/api/accounts/{accountId}/folders
Example:
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/zoho-mail/api/accounts/{accountId}/folders') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
Response:
{ "status": { "code": 200, "description": "success" }, "data": [ { "folderId": "1367000000000008014", "folderName": "Inbox", "folderType": "Inbox", "path": "/Inbox", "imapAccess": true, "isArchived": 0, "URI": "https://mail.zoho.com/api/accounts/1367000000000008002/folders/1367000000000008014" }, { "folderId": "1367000000000008016", "folderName": "Drafts", "folderType": "Drafts", "path": "/Drafts", "imapAccess": true, "isArchived": 0 } ] }
POST /zoho-mail/api/accounts/{accountId}/folders Content-Type: application/json{ "folderName": "My Custom Folder" }
PUT /zoho-mail/api/accounts/{accountId}/folders/{folderId} Content-Type: application/json{ "folderName": "Renamed Folder" }
DELETE /zoho-mail/api/accounts/{accountId}/folders/{folderId}
GET /zoho-mail/api/accounts/{accountId}/labels
Example:
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/zoho-mail/api/accounts/{accountId}/labels') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
POST /zoho-mail/api/accounts/{accountId}/labels Content-Type: application/json{ "labelName": "Important" }
PUT /zoho-mail/api/accounts/{accountId}/labels/{labelId} Content-Type: application/json{ "labelName": "Updated Label" }
DELETE /zoho-mail/api/accounts/{accountId}/labels/{labelId}
GET /zoho-mail/api/accounts/{accountId}/messages/view?folderId={folderId}
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
| long | Folder ID to list messages from |
| integer | Number of messages to return (default: 50) |
| integer | Offset for pagination |
| string | Sort field (e.g., ) |
| boolean | for ascending, for descending |
Example:
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/zoho-mail/api/accounts/{accountId}/messages/view?folderId={folderId}&limit=10') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
GET /zoho-mail/api/accounts/{accountId}/messages/search?searchKey={query}
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
| string | Search query |
| integer | Number of results to return |
| integer | Offset for pagination |
Example:
python <<'EOF' import urllib.request, os, json import urllib.parse query = urllib.parse.quote('from:sender@example.com') req = urllib.request.Request(f'https://gateway.maton.ai/zoho-mail/api/accounts/{{accountId}}/messages/search?searchKey={query}') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
GET /zoho-mail/api/accounts/{accountId}/folders/{folderId}/messages/{messageId}/content
Example:
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/zoho-mail/api/accounts/{accountId}/folders/{folderId}/messages/{messageId}/content') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
GET /zoho-mail/api/accounts/{accountId}/folders/{folderId}/messages/{messageId}/header
GET /zoho-mail/api/accounts/{accountId}/folders/{folderId}/messages/{messageId}/details
GET /zoho-mail/api/accounts/{accountId}/messages/{messageId}/originalmessage
POST /zoho-mail/api/accounts/{accountId}/messages Content-Type: application/json{ "fromAddress": "sender@yourdomain.com", "toAddress": "recipient@example.com", "subject": "Email Subject", "content": "Email body content", "mailFormat": "html" }
Request Body Fields:
| Field | Type | Required | Description |
|---|---|---|---|
| string | Yes | Sender's email address |
| string | Yes | Recipient's email address |
| string | Yes | Email subject |
| string | Yes | Email body content |
| string | No | CC recipient |
| string | No | BCC recipient |
| string | No | or (default: ) |
| string | No | or for read receipt |
| string | No | Character encoding (default: ) |
Example - Send Email:
python <<'EOF' import urllib.request, os, json data = json.dumps({ "fromAddress": "sender@yourdomain.com", "toAddress": "recipient@example.com", "subject": "Hello from Zoho Mail API", "content": "<h1>Hello!</h1><p>This is a test email.</p>", "mailFormat": "html" }).encode() req = urllib.request.Request('https://gateway.maton.ai/zoho-mail/api/accounts/{accountId}/messages', data=data, method='POST') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Content-Type', 'application/json') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
Scheduling Parameters (Optional):
| Field | Type | Description |
|---|---|---|
| boolean | Enable scheduling |
| integer | 1-5 for preset times; 6 for custom |
| string | Required if scheduleType=6 (e.g., ) |
| string | Required if scheduleType=6 (format: ) |
POST /zoho-mail/api/accounts/{accountId}/messages/{messageId} Content-Type: application/json{ "fromAddress": "sender@yourdomain.com", "toAddress": "recipient@example.com", "subject": "Re: Original Subject", "content": "Reply content" }
POST /zoho-mail/api/accounts/{accountId}/messages Content-Type: application/json{ "fromAddress": "sender@yourdomain.com", "toAddress": "recipient@example.com", "subject": "Draft Subject", "content": "Draft content", "mode": "draft" }
PUT /zoho-mail/api/accounts/{accountId}/updatemessage Content-Type: application/json{ "messageId": ["messageId1", "messageId2"], "folderId": "folderId", "mode": "markAsRead" }
Mode Options:
markAsRead - Mark messages as readmarkAsUnread - Mark messages as unreadmoveMessage - Move messages (requires destfolderId)setFlag - Set flag (requires flagid)applyLabel - Apply labels (requires labelId)archive - Archive messagesunArchive - Unarchive messagesspam - Mark as spamnotSpam - Mark as not spamExample - Mark as Read:
python <<'EOF' import urllib.request, os, json data = json.dumps({ "messageId": ["1234567890123456789"], "folderId": "9876543210987654321", "mode": "markAsRead" }).encode() req = urllib.request.Request('https://gateway.maton.ai/zoho-mail/api/accounts/{accountId}/updatemessage', data=data, method='PUT') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Content-Type', 'application/json') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
Flag messages with a color/status indicator.
PUT /zoho-mail/api/accounts/{accountId}/updatemessage Content-Type: application/json{ "mode": "setFlag", "messageId": ["messageId1", "messageId2"], "flagid": "important" }
Flag ID Options:
| Flag ID | Description |
|---|---|
| Info flag (blue) |
| Important flag (red) |
| Follow-up flag (orange) |
| Remove flag |
Optional Parameters:
threadId - Array of thread IDs (alternative to messageId)isFolderSpecific - Set to true if using folderIdfolderId - Folder ID (required if isFolderSpecific is true)isArchive - Set to true to include archived emailsExample - Flag as Important:
python <<'EOF' import urllib.request, os, json data = json.dumps({ "mode": "setFlag", "messageId": ["1234567890123456789"], "flagid": "important", "isFolderSpecific": True, "folderId": "9876543210987654321" }).encode() req = urllib.request.Request('https://gateway.maton.ai/zoho-mail/api/accounts/{accountId}/updatemessage', data=data, method='PUT') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Content-Type', 'application/json') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
Apply one or more labels to messages or threads.
PUT /zoho-mail/api/accounts/{accountId}/updatemessage Content-Type: application/json{ "mode": "applyLabel", "messageId": ["messageId1"], "labelId": ["labelId1", "labelId2"] }
Required Parameters:
mode - Must be "applyLabel"messageId or threadId - Array of message/thread IDslabelId - Array of label IDs to applyOptional Parameters:
isFolderSpecific - Set to true if using folderIdfolderId - Folder ID (required if isFolderSpecific is true)isArchive - Set to true to include archived emailsExample - Apply Labels:
python <<'EOF' import urllib.request, os, json data = json.dumps({ "mode": "applyLabel", "messageId": ["1234567890123456789"], "labelId": ["111222333444555666", "777888999000111222"], "isFolderSpecific": True, "folderId": "9876543210987654321" }).encode() req = urllib.request.Request('https://gateway.maton.ai/zoho-mail/api/accounts/{accountId}/updatemessage', data=data, method='PUT') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Content-Type', 'application/json') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
Note: Get label IDs by calling
GET /zoho-mail/api/accounts/{accountId}/labels first.
DELETE /zoho-mail/api/accounts/{accountId}/folders/{folderId}/messages/{messageId}
POST /zoho-mail/api/accounts/{accountId}/messages/attachments Content-Type: multipart/form-data
GET /zoho-mail/api/accounts/{accountId}/folders/{folderId}/messages/{messageId}/attachmentinfo
GET /zoho-mail/api/accounts/{accountId}/folders/{folderId}/messages/{messageId}/attachments/{attachmentId}
Zoho Mail uses offset-based pagination:
GET /zoho-mail/api/accounts/{accountId}/messages/view?folderId={folderId}&start=0&limit=50
start: Offset index (default: 0)limit: Number of records to return (default: 50)For subsequent pages, increment
start by limit:
start=0&limit=50start=50&limit=50start=100&limit=50const response = await fetch( 'https://gateway.maton.ai/zoho-mail/api/accounts', { headers: { 'Authorization': `Bearer ${process.env.MATON_API_KEY}` } } ); const data = await response.json();
import os import requestsresponse = requests.get( 'https://gateway.maton.ai/zoho-mail/api/accounts', headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'} ) data = response.json()
/api/accounts to get your account IDfromAddress must be associated with the authenticated accountINVALID_OAUTHSCOPE error, contact Maton support at support@maton.ai with the specific operations/APIs you need and your use-casecurl -g when URLs contain brackets to disable glob parsingjq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments| Status | Meaning |
|---|---|
| 400 | Missing Zoho Mail connection or invalid request |
| 401 | Invalid or missing Maton API key |
| 429 | Rate limited |
| 4xx/5xx | Passthrough error from Zoho Mail API |
MATON_API_KEY environment variable is set:echo $MATON_API_KEY
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
zoho-mail. For example:https://gateway.maton.ai/zoho-mail/api/accountshttps://gateway.maton.ai/api/accountsNo automatic installation available. Please visit the source repository for installation instructions.
View Installation Instructions1,500+ AI skills, agents & workflows. Install in 30 seconds. Part of the Torly.ai family.
© 2026 Torly.ai. All rights reserved.