Repository navigation
Expose unauthenticated mail discovery and recorded authentication results - #86
Conversation
- Verdicts are strings, not an enum, and the projection keeps only string values, so a verdict the API adds later cannot fail get_message/get_thread. - Drop the raw authentication_results copy: only the MCP adapter strips undeclared fields, so the other adapters returned both shapes. - Carry the API's caveats into the field descriptions (compare dkimDomain with From, do not reject on a DMARC fail alone) and mark when to delete the projection. - Add includeBlocked to list_messages/list_threads, say both opt-ins need the matching label_*_read permission, and say search always excludes blocked and unauthenticated mail. - Add include_unauthenticated to the Python list_threads. - Test the camelCase branch, an unknown verdict, the non-MCP adapter, and that the tools expose every include* opt-in the SDK reads. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
duharry0915
left a comment
There was a problem hiding this comment.
Checked the claims against agentmail-api and the Fern definition. The blocked meaning, the label_*_read permission names, the silent exclusion without the permission, and search always excluding restricted mail all hold. Main gap: list/search message items carry authentication_results too and aren't covered (inline on getMessage). The rest are inline.
One note outside the diff: Python get_thread (python/src/agentmail_toolkit/functions.py) returns the SDK model as-is (extra='allow'), so each message's raw snake_case authentication_results passes through unprojected, including undocumented keys. With Node now projecting, the two toolkits disagree on the field's shape and on what gets filtered.
- list_messages and search_messages items carry authentication_results too: project them and declare authenticationResults on MessageItemSchema. - Project the camelCase field an SDK that types it returns the same way, emit only keys with string values, and derive the keys from MessageAuthenticationResultsSchema so a new key needs one edit. - Guard a thread or page that comes back without messages. - Describe the unauthenticated label as the API defines it, and say on all four restricted-label opt-ins (Node and Python) that labels alone does not include them and that each needs its label_*_read permission. - The Python opt-in test now compares against the SDK's list signature. - Bump to 0.17.0: the non-MCP adapters no longer return the raw authentication_results key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
On the Python |
duharry0915
left a comment
There was a problem hiding this comment.
Verified bf3b430 against the earlier comments: list/search items are projected, the typed-SDK path is filtered, descriptions match the API, and build, lint and all tests pass. Worth an issue for the deferred follow-up (strip every adapter's results, and Python's, to the output schema in one shared place) so it doesn't get lost.
Messages labeled
unauthenticated(orblocked) can be fetched by ID but cannot be discovered through the toolkit's message or thread listing tools, because those tools omit the API's explicit opt-ins. Message results also discard the API's recorded authentication verdicts.Add optional
includeUnauthenticatedandincludeBlockedtolist_messagesandlist_threads(andinclude_unauthenticatedto the Pythonlist_threads). Return the publicauthenticationResultsfields onget_message, on messages insideget_thread, and onlist_messages/search_messagesitems.The pinned SDK (0.5.46) passes the field through in snake_case, so the toolkit projects it to camelCase, keeping only string values of the keys
MessageAuthenticationResultsSchemadeclares, and drops the raw copy. An SDK that types the field (camelCase) goes through the same projection. Delete the snake_case branch once the toolkit requires that SDK; the Fern definition already declares the field. Verdicts are strings, so a value the API adds later can't fail a read. The MCP output allowlist still excludes raw headers, tenant identifiers and diagnostic fields.The descriptions carry the API's caveats: compare
dkimDomainwith the From domain before trusting a DKIM pass, and don't reject mail on a DMARC fail alone. They also define theunauthenticatedlabel as the API does (no mechanism passed, or DMARC failed under a none policy). All four restricted-label opt-ins, in both toolkits, now say thatlabelsalone doesn't include that mail and that each needs itslabel_*_readpermission, without which the API leaves the mail out silently. The search tools say they always exclude blocked and unauthenticated mail. Defaults, labels, authentication checks and backend permission enforcement stay unchanged.Breaking for non-MCP adapters (version 0.17.0): the base toolkit and the ai-sdk, LangChain and clawdbot adapters used to return the SDK's raw
authentication_resultskey fromget_message/get_thread. They now return only the projectedauthenticationResults, so code readingresult.authentication_resultsgetsundefinedafter upgrading.Validation: all 799 Node tests and 62 Python tests pass. Tests cover:
include*opt-in the list tools don't exposepnpm lintandpnpm build(including declaration generation) pass. Repository-widetsc --noEmitstill reports existing example-module, contract-test cast and tsup-config import errors outside this change.Follow-ups:
headersandorganization_id. Stripping every adapter's result to its output schema in one shared place is a separate change.🤖 Generated with Claude Code