inkbox-ai/inkbox/inkbox-python

Claude Code and agent skill by inkbox-ai/inkbox

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Use when writing Python code that imports from `inkbox`, uses `pip install inkbox`, or when adding email, mailbox imports, phone, text/SMS, iMessage, A2A task/message history, contacts, notes, contact rules, vault, tunnels, mailbox storage, mail clients (IMAP/SMTP), or agent identity features using the Inkbox Python SDK.

Install

npx vskill@latest install inkbox-ai/inkbox/inkbox-python

SKILL.md

Inkbox Python SDK

API-first communication infrastructure for AI agents — email, phone, encrypted vault, and identities.

Install & Init

python
pip install inkbox

Always use the context manager — it manages the underlying HTTP session:

python
from inkbox import Inkbox
with Inkbox(api_key="ApiKey_...") as inkbox:
...

Constructor: Inkbox(api_key, base_url="https://inkbox.ai", timeout=30.0)

Core Model

Inkbox (admin-only client)
├── .create_identity(handle) → AgentIdentity
├── .get_identity(handle) → AgentIdentity
├── .list_identities() → list[AgentIdentitySummary]
├── .mailboxes → MailboxesResource
├── .phone_numbers → PhoneNumbersResource
├── .texts → TextsResource
├── .imessages → IMessagesResource
├── .imessage_contact_rules → IMessageContactRulesResource
├── .mail_identity_contact_rules → MailIdentityContactRulesResource (keyed by agent_handle)
├── .phone_identity_contact_rules → PhoneIdentityContactRulesResource (keyed by agent_handle)
├── .signing_keys → SigningKeysResource (per-identity: create_or_rotate/get_status)
├── .mail_contact_rules → MailContactRulesResource (DEPRECATED — per-mailbox)
├── .phone_contact_rules → PhoneContactRulesResource (DEPRECATED — per-number)
├── .sms_opt_ins → SmsOptInsResource
├── .contacts → ContactsResource (.permissions, .communication_policy, .facts, .correspondence, .access, .vcards)
├── .notes → NotesResource (.access)
├── .vault → VaultResource
├── .whoami() → WhoamiResponse
└── .create_signing_key() → SigningKey (DEPRECATED — org-level; use .signing_keys)
AgentIdentity (identity-scoped helper)
├── .mailbox → IdentityMailbox | None
├── .phone_number → IdentityPhoneNumber | None
├── .mail_filter_mode / .phone_filter_mode → FilterMode
├── .credentials → Credentials (requires vault unlocked)
├── .list_mail_contact_rules() / .create_mail_contact_rule(...) / .get_/.update_/.delete_
├── .list_phone_contact_rules() / .create_phone_contact_rule(...) / ... (writes require admin credentials)
├── .get_signing_key_status() / .create_signing_key()
├── .list_contact_communication_policies() → ContactCommunicationPolicyPage
├── mail methods (requires assigned mailbox)
├── phone methods (requires assigned phone number)
└── text methods (requires assigned phone number)

An identity must have a channel assigned before you can use mail/phone methods. If not assigned, an InkboxError is raised with a clear message.

Agent Signup

For the full agent self-signup flow (register, verify, check status, restrictions, and direct API examples), read the shared reference:

See: skills/inkbox-agent-self-signup/SKILL.md

Python SDK methods: Inkbox.signup(...), Inkbox.verify_signup(api_key, ...), Inkbox.resend_signup_verification(api_key), Inkbox.get_signup_status(api_key).

Identities

Handles are fixed at creation. Change the display name to update an agent's presentation.

python
identity = inkbox.create_identity("sales-agent")
identity = inkbox.get_identity("sales-agent")
identities = inkbox.list_identities() # → list[AgentIdentitySummary]
identity.update(display_name="Sales assistant")
identity.refresh() # re-fetch from API, updates cached channels
identity.delete() # cascades: mailbox + tunnel + phone-number release

Channel Management

python
# Identity is created with a mailbox AND tunnel atomically — both come back on the response
print(identity.email_address) # e.g. "sales-agent@inkboxmail.com"
print(identity.tunnel.public_host) # e.g. "sales-agent.inkboxwire.com"
# Phone numbers are still opt-in
phone = identity.provision_phone_number(type="local", state="NY") # local only; toll_free is rejected (422)
print(phone.number) # e.g. "+12125551234"
# Release the phone number (vendor + local)
identity.release_phone_number()

Mailboxes and tunnels are not separately linkable — they are 1:1 with their owning identity. Use inkbox.create_identity() to provision both; use identity.delete() to remove both (cascade).

Mail

Import historical mail
python
from inkbox import MailImportFormat
created = inkbox.mailboxes.imports.create(
email,
source_format=MailImportFormat.AUTO,
original_addresses=["old@example.com"],
)
inkbox.mailboxes.imports.upload(created.upload, "archive.mbox")
inkbox.mailboxes.imports.start(email, str(created.job.id))
job = inkbox.mailboxes.imports.wait(email, str(created.job.id), poll_interval=5)

Formats: auto, mbox, eml, zip. A ZIP may hold .eml and/or .mbox files (a Gmail Takeout ZIP imports as-is); other entries, including nested archives, are ignored. wait returns all terminal states; failure/cancellation are job results, not transport errors. A timeout does not cancel. Counters are cumulative and never go backwards, so a stalled counter is a signal, not normal churn; counters may still remain unchanged while a slow message is processed, and they must not be treated as a percentage. Jobs run one at a time per organization and share overall import capacity, so a long queued stretch is normal; do not cancel and recreate. Unsafe imported content may be rejected.

Upload targets expire after 5 minutes: refresh_upload_target(email, job_id) and upload again, or cancel the job so it does not hold the mailbox for 24 hours. Limits: 1 GiB per upload, 50 MiB per message, 100,000 messages and 20 original_addresses per job, 65,000 entries per ZIP, 20 jobs per organization per 24 hours (MailImportQuotaExceededError.retry_after_seconds), and one in-flight import per mailbox.

Send
python
sent = identity.send_email(
to=["user@example.com"],
subject="Hello",
body_text="Hi there!", # plain text (optional)
body_html="<p>Hi there!</p>", # HTML (optional)
cc=["cc@example.com"], # optional
bcc=["bcc@example.com"], # optional
in_reply_to_message_id=sent.id, # for threaded replies
attachments=[{ # optional
"filename": "report.pdf",
"content_type": "application/pdf",
"content_base64": "<base64>",
}, {
"filename": "chart.png", # inline image: set content_id and
"content_type": "image/png", # reference it from body_html as
"content_base64": "<base64>", # <img src="cid:chart">. needs body_html
"content_id": "chart", # + image/*, unique per send; not on forwards.
}],
track_opens=True, # optional; embed a tracking pixel
)
# track_opens tracks sends only when an HTML body is present. Opens
# surface on the returned Message as sent.first_opened_at / sent.open_count
# (approximate — proxy prefetch inflates it, the per-window debounce
# collapses repeats, so it can read above or below the true count; prefer
# first_opened_at. pixels can also raise spam scores).
#
# send_email / reply_all_email / forward_email all raise
# StorageLimitExceededError (402) when the mailbox is at its storage cap —
# see "Storage cap (402)" below.
Drafts
python
from inkbox import DraftRecipients
draft = identity.create_email_draft(
subject="Work in progress",
idempotency_key="draft-create-2026-08-19-1",
)
for saved in identity.iter_email_drafts():
print(saved.id, saved.generation)
current = identity.get_email_draft(draft.id)
current = identity.update_email_draft(
current.id,
generation=current.generation,
recipients=DraftRecipients(to=["user@example.com"]),
subject=None, # explicit null clears; omission leaves unchanged
)
current = inkbox.drafts.add_attachments(
identity.email_address,
current.id,
generation=current.generation,
attachments=[{
"filename": "notes.txt",
"content_type": "text/plain",
"content_base64": "bm90ZXM=",
}],
)
part = current.attachment_metadata[0]
content = inkbox.drafts.download_attachment(
identity.email_address, current.id, part.part_index, generation=current.generation
)
current = inkbox.drafts.remove_attachment(
identity.email_address, current.id, part.part_index, generation=current.generation
)
copy = identity.duplicate_email_draft(current.id, generation=current.generation)
identity.delete_email_draft(copy.id, generation=copy.generation)
sent = identity.send_email_draft(current.id, generation=current.generation)

Drafts share the mailbox's standard Drafts folder with connected mail clients. Reuse one idempotency_key and the exact same request when retrying a logical create after an ambiguous result. Use a new key after the original draft is sent or deleted. Forward-only options require forward_message_id. Use the latest returned generation for every mutation. A part_index belongs to the generation that returned it, so refresh attachment metadata after edits.

Successful send returns a Message and removes the draft; an exact-generation retry may return the same sent message. HTTP 409 errors remain structured on InkboxAPIError.detail["error"]: refresh on draft_generation_conflict and retry the same ID and generation on draft_send_in_progress. Never resend draft_delivery_uncertain; after checking sent mail, duplicate or delete it instead.

Read
python
# Iterate all messages — pagination handled automatically (Iterator[Message])
for msg in identity.iter_emails():
print(msg.subject, msg.from_address, msg.is_read)
# Filter by direction
for msg in identity.iter_emails(direction="inbound"): # or "outbound"
...
# Unread only (client-side filtered)
for msg in identity.iter_unread_emails():
...
# Mark as read
ids = [msg.id for msg in identity.iter_unread_emails()]
identity.mark_emails_read(ids)
identity.mark_emails_unread(ids) # batch counterpart
# Note: fetching a single inbound message by id (inkbox.messages.get) with
# an API key marks it read server-side; iterating does not, so
# mark_emails_read is the way to clear unread for list-only workflows.
# is_read (agent consumed via API) is distinct from first_opened_at
# (recipient's mail client loaded the tracking pixel).
# Get full thread (oldest-first)
thread = identity.get_thread(msg.thread_id)
for m in thread.messages:
print(f"[{m.from_address}] {m.subject}")
Thread Folders

Threads carry a folder field: inbox, spam, archive, or blocked (server-assigned, never client-set).

python
from inkbox import ThreadFolder
# Thread.folder / ThreadDetail.folder is always one of the four values above.

Low-level folder listing / per-thread updates (list(folder=…), list_folders(email), update(..., folder=…)) live on ThreadsResource. Passing folder="blocked" to update raises ValueError before the HTTP call.

Storage cap (402)

Every mailbox has a plan storage cap. All three send paths — send_email, reply_all_email, and forward_email (and the inkbox.messages.* equivalents) — raise StorageLimitExceededError (HTTP 402) when the send would push the mailbox over it.

python
from inkbox import StorageLimitExceededError
try:
identity.send_email(to=["user@example.com"], subject="Hi", body_text="…")
except StorageLimitExceededError as e:
print(e.message) # human sentence, includes the limit
print(e.limit_bytes) # e.g. 2147483648 (2 GiB)
print(e.upgrade_url) # console billing page
# Free space — reclaim is immediate — or upgrade the plan:
inkbox.messages.delete(identity.email_address, "<message-uuid>")
inkbox.threads.delete(identity.email_address, "<thread-uuid>")

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 90 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
100
Repository forks
26
7-day trend score
0

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/inkbox-ai/inkbox/inkbox-python/badge)](https://verified-skill.com/skills/inkbox-ai/inkbox/inkbox-python)

Something wrong with this skill or its page? Tell us.