← Public packages
@noah/hey-email
HEY.com email integration with Kody: search threads, read messages/attachments, create drafts, and send with explicit confirmation.
AGENTS.md
56 lines · 2.7 KB · Markdown@noah/hey-email
Imports
import identity from 'kody:@noah/hey-email'
import search from 'kody:@noah/hey-email/search'
import listBoxes from 'kody:@noah/hey-email/boxes'
import getTopic from 'kody:@noah/hey-email/topic'
import getEntries from 'kody:@noah/hey-email/entries'
import getMessage from 'kody:@noah/hey-email/message'
import listAndDownloadPdfs from 'kody:@noah/hey-email/attachments'
import { listDrafts, createReplyDraft, createDraft, getDraft, sendDraft, sendMessage, sendReply, getReplyPrefill } from 'kody:@noah/hey-email/drafts'
import { sendMessage } from 'kody:@noah/hey-email/send'
import createReplyDraft from 'kody:@noah/hey-email/reply'Smoke tests
await identity()
await search({ q: 'receipt', date: 'last_7_days' })
await listDrafts()Edge cases
- Auth is
{{secret:heyToken}}only — never paste tokens. - Credentials are only sent to
app.hey.com;resolveHeyUrlrefuses other origins. - Prefer
/advanced_search.json?q=for search; Search HTML endpoints return 406 without Accept handling. - Topic reads use
/topics/{id}.jsonand/topics/{id}/entries.json. - Full message body + trix attachments:
/messages/{entryId}.jsonviagetMessage. Entries list does not include attachment markup — always fetch the message. - PDF download: parse
data-trix-attachmentJSON ("→"), then GEThttps://app.hey.com+ url with the same bearer (follow redirects). - The CLI auto-refreshes its own token, but the
heyTokensecret is a static copy and does not. OnHEY 401, have the user runhey auth refresh && hey auth tokenand update the secret.hey auth statusreports the localexpires_at. - A
hey auth login --cookielogin stores a cookie, not a bearer token;hey auth tokenrefuses to print it and this package cannot use it. - Never auto-send.
createReplyDraft/createDraftomittoso HEY stores a draft.sendMessage,sendReply, andsendDraftare dry-run unless{ confirm: true }. - When the user explicitly asks to email someone, call
sendMessage({ to, subject, text, confirm: true }). Do not send on a reminder job. - New send: POST
/messages.jsonwith{ acting_sender_id, subject, content, to }. Reply send: POST/entries/{id}/replies.jsonwith the same plusto. Draft send: PUT/messages/{id}.jsonwithto. - Prefill: GET
/entries/{entryId}/replies/new.json. Create draft: POST/entries/{entryId}/replies.jsonwith{ acting_sender_id, subject, content }only. - List drafts: GET
/entries/drafts.json. Edit URL is/messages/{id}/edit.
Attachments
./attachments parses data-trix-attachment JSON and nested
<action-text-attachment> / ActiveStorage .pdf URLs (some senders wrap the
PDF inside an HTML trix blob).