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://api.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://api.maton.ai/zoho-mail/{native-api-path}
Maton 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://api.maton.ai.
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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://api.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://api.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": "{connection_id}",
"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://api.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://api.maton.ai/zoho-mail/api/accounts')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '{connection_id}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If you have multiple connections, always include this header to ensure requests go to the intended account.
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://api.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://api.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://api.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 |
|---|---|---|
| ----------- | ------ | ------------- |
folderId | long | Folder ID to list messages from |
limit | integer | Number of messages to return (default: 50) |
start | integer | Offset for pagination |
sortBy | string | Sort field (e.g., date) |
sortOrder | boolean | true for ascending, false for descending |
Example:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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 |
|---|---|---|
| ----------- | ------ | ------------- |
searchKey | string | Search query |
limit | integer | Number of results to return |
start | 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://api.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://api.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 |
|---|---|---|---|
| ------- | ------ | ---------- | ------------- |
fromAddress | string | Yes | Sender's email address |
toAddress | string | Yes | Recipient's email address |
subject | string | Yes | Email subject |
content | string | Yes | Email body content |
ccAddress | string | No | CC recipient |
bccAddress | string | No | BCC recipient |
mailFormat | string | No | html or plaintext (default: html) |
askReceipt | string | No | yes or no for read receipt |
encoding | string | No | Character encoding (default: UTF-8) |
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://api.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 |
|---|---|---|
| ------- | ------ | ------------- |
isSchedule | boolean | Enable scheduling |
scheduleType | integer | 1-5 for preset times; 6 for custom |
timeZone | string | Required if scheduleType=6 (e.g., GMT 5:30) |
scheduleTime | string | Required if scheduleType=6 (format: MM/DD/YYYY HH:MM:SS) |
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://api.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 | Info flag (blue) |
important | Important flag (red) |
followup | Follow-up flag (orange) |
flag_not_set | 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://api.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://api.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://api.maton.ai/zoho-mail/api/accounts',
{
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`
}
}
);
const data = await response.json();
import os
import requests
response = requests.get(
'https://api.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://api.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://api.maton.ai/zoho-mail/api/accountshttps://api.maton.ai/api/accounts共 3 个版本