-
Notifications
You must be signed in to change notification settings - Fork 82
Description
Describe the bug
Draft creation fails with NylasApiError: only JSON and multipart supported when using the Nylas Python SDK v6.13.1+. The Nylas API returns
a 400 error rejecting the draft creation request, even though the request appears to be properly formatted JSON.
Root Cause:
In v6.13.1 (commit d226ff1, PR #442), the HTTP client was changed to manually serialize JSON using json.dumps(request_body,
ensure_ascii=False) and pass it via the data= parameter instead of using the json= parameter in requests.request(). While this fixed UTF-8
encoding for multipart requests, it appears to have broken JSON-only requests for draft creation.
The issue is that when using data=json_string instead of json=dict, the requests library doesn't automatically set the correct
Content-Type header, or the manually added application/json; charset=utf-8 header is not being accepted by the Nylas API for draft
creation.
To Reproduce
from nylas import Client
from nylas.models.drafts import CreateDraftRequest
# Initialize client
nylas = Client(api_key="your_api_key", api_uri="https://api.us.nylas.com")
# Attempt to create a draft
draft_request = CreateDraftRequest(
to=[{"email": "[email protected]"}],
subject="Test Subject",
body="Test body content"
)
try:
# This will fail with "only JSON and multipart supported"
response = nylas.drafts.create(
grant_id="your_grant_id",
request_body=draft_request
)
except Exception as e:
print(f"Error: {e}")
# Output: NylasApiError: only JSON and multipart supported
Expected behavior
The draft should be created successfully without errors. The Nylas API should accept the JSON request and return the created draft object.
Workaround:
Bypass the SDK's drafts.create() method and use requests directly with the json= parameter:
import requests
from nylas.models.response import Response
from nylas.models.drafts import Draft
# Get API credentials from the SDK client
api_server = nylas.drafts._http_client.api_server
api_key = nylas.drafts._http_client.api_key
url = f"{api_server}/v3/grants/{grant_id}/drafts"
headers = {
"Authorization": f"Bearer {api_key}",
"X-Nylas-API-Wrapper": "python",
}
# Use requests directly with json= parameter
http_response = requests.post(url, headers=headers, json=draft_request_dict, timeout=30)
if http_response.status_code >= 400:
raise Exception(f"Draft creation failed: {http_response.json()}")
draft_data = http_response.json()
response = Response.from_dict(draft_data, Draft, http_response.headers)
This workaround succeeds because requests.post() with json=dict properly handles Content-Type headers.
SDK Version:
- Broken: v6.13.1 and later (including v6.13.1, v6.14.0, v6.14.1, v6.14.2)
- Last working: v6.13.0 and earlier
Additional context
The breaking change was introduced in commit d226ff1 (PR #442) which modified nylas/handler/http_client.py:
- Changed from: requests.request(..., json=request_body, data=data)
- Changed to: requests.request(..., data=json_data or data) where json_data = json.dumps(request_body, ensure_ascii=False)
- Changed Content-Type header from application/json to application/json; charset=utf-8
While PR #442 successfully fixed UTF-8 encoding issues for multipart requests with large attachments, it appears to have broken standard
JSON requests for draft creation. The requests library handles the json= parameter differently than data= with a pre-serialized JSON
string, particularly regarding header management.
Suggested Fix:
Consider using json= parameter for JSON-only requests and data= with manual serialization only for multipart/form-data requests where
UTF-8 encoding is needed.