Skip to content
NEWTry Pilot Cloud

Dead Simple Email · io.pilot.deadsimple

Dead Simple Email

An email identity your agent provisions for itself, then uses to send, receive, and read its own signup codes. See setup and usage details.

Communications · Live on the catalogue

$ pilotctl appstore install io.pilot.deadsimple
Version
v0.1.0
Methods
19
Size
—
Permissions
4 declared
Platforms
macOS · Linux

About Dead Simple Email

Dead Simple Email gives an agent a real, deliverable email identity — not a sandbox — and it can get one entirely on its own. A single call to deadsimple.signup returns an account, an API key and a live inbox. No dashboard, no verification email, no human in the loop.

The method agents reach for most is deadsimple.get_verification_code. It pulls the one-time code or magic link straight out of the newest inbound message, so an agent can sign itself up for a third-party service or clear a 2FA prompt without ever parsing an email body. Filter by sender and by timestamp so a stale code is never returned. This is what turns "the provider emails you a code" from a dead end into a step.

From there the agent sends, replies on-thread, reply-alls, forwards, reads full messages with headers and attachments, and walks whole conversation threads over one REST API.

Underneath is real sending infrastructure: DKIM-signed egress through a dedicated MTA, bounce and complaint handling, suppression lists, and optional open and click tracking. Inbound mail can be pushed to HMAC-SHA256 signed webhooks that retry on exponential backoff. A supervisor agent can watch every inbox in a workspace at once with list_all_messages, and inboxes can be created in bulk, tagged, and torn down when a throwaway identity is finished.

Tiers. A self-provisioned agent account starts on trial: 1 inbox, 10 sends an hour, 25 a day. Calling deadsimple.claim with an email a human controls, then deadsimple.claim_verify, moves it to the Free plan — 5 inboxes and 5,000 emails a month — keeping the same API key, inboxes and history. Paid plans scale to 500 inboxes, 25 custom domains, and 1,000 requests a minute.

Edge cases. A 429 with code trial_send_limit_exceeded is a quota signal, not a transient failure — do not blindly retry, claim the account instead. Pagination is cursor-based. Spam is excluded from list_messages unless include_spam is true. Delete throwaway inboxes when finished so they stop counting against the quota.

Methods · 19

deadsimple.signupSTART HERE if you have no key. Provisions a Dead Simple account, an API key and a live inbox in one call, with no human, no dashboard and no verification email. Returns {account_id, api_key, inbox}. Save api_key as the DEADSIMPLE_API_KEY secret — every other method authenticates with it. Idempotent per Idempotency-Key, so a retry after a dropped connection returns the same account rather than a second one. The account starts on the trial tier: 1 inbox, 10 sends an hour, 25 a day.deadsimple.claimStart lifting the trial caps by attaching an email address a human controls. Sends a 6-digit code to that address; pass it to deadsimple.claim_verify to finish. Your existing API key, inboxes and message history are untouched by the upgrade.deadsimple.claim_verifyConfirm the code from deadsimple.claim and move the account from trial to the Free plan (5 inboxes, 5,000 emails a month). The same API key keeps working.deadsimple.create_inboxCreate a real, deliverable email inbox in one call. Returns an inbox_id and a live address that can send and receive immediately — no SMTP setup, no DNS, no mailbox provisioning. Use this when you already have a key and want an additional identity.deadsimple.list_inboxesList the inboxes this key can see, newest first. Cursor-paginated: pass the cursor from the previous response for the next page.deadsimple.get_inboxFetch one inbox: its address, display name, tags, status, and counters.deadsimple.delete_inboxPermanently delete an inbox and its stored messages. IRREVERSIBLE. Use when a throwaway identity is finished so it stops counting against the inbox quota.deadsimple.send_emailSend an email from one of your inboxes. Plain text or HTML, cc/bcc, base64 attachments, scheduled send, and optional open/click tracking. Real DKIM-signed egress, not a test harness. On the trial tier this is capped at 10 an hour and 25 a day; a 429 with code trial_send_limit_exceeded is a quota signal, not a transient failure.deadsimple.get_verification_codeTHE method agents reach for. Pulls the one-time code or magic link straight out of the newest inbound message, so a signup or 2FA prompt can be cleared without parsing an email body. Non-blocking: returns found=false if nothing has arrived, so poll every 2-3 seconds for up to a minute after triggering the mail. Set `since` to a timestamp taken BEFORE you triggered it, and `from_contains` to the sender domain, so a stale code is never returned.deadsimple.list_messagesList messages in an inbox, newest first, with sender, subject, snippet, and labels. Spam is excluded unless include_spam is true. Cursor-paginated.deadsimple.get_messageGet one message in full: headers, plain-text and HTML bodies, and attachment metadata.deadsimple.replyReply to the sender of a message. Threading headers are set automatically so the reply lands in the same conversation — never hand-build In-Reply-To.deadsimple.reply_allReply to the sender and every other recipient of a message, with threading headers set automatically.deadsimple.forwardForward a message, with its attachments, to new recipients.deadsimple.list_threadsList conversation threads in an inbox, each with its latest message, so an agent can track ongoing exchanges instead of loose messages.deadsimple.get_threadGet a full conversation thread with every message in order — the context an agent needs before replying.deadsimple.get_attachmentGet a time-limited signed download URL for an attachment. The link expires in one hour.deadsimple.list_all_messagesList messages across every inbox this key can see, newest first. For a supervisor agent watching many identities at once — cheaper than iterating inboxes.deadsimple.create_webhookRegister an HMAC-SHA256 signed webhook for inbound mail, bounces, and complaints, so long-running work does not have to poll list_messages in a loop. Deliveries retry on exponential backoff and every attempt is logged.

Full usage demo

When your agent needs an email address of its own: to sign itself up for a third-party service and read the code back, or to send and receive real mail as part of a task.

Run this first — Get an account, an API key and a live inbox in one callCall
pilotctl appstore call io.pilot.deadsimple deadsimple.signup '{"label":"my-agent"}'
→{"data":{"account_id":"...","api_key":"dse_...","inbox":{"inbox_id":"...","email":"...@box1.deadsimple.email"},"plan":{"plan":"trial","inbox_limit":1,"sends_per_hour":10}}}

Everything is under data. Save data.api_key as DEADSIMPLE_API_KEY — it is shown once. Already have a key? Skip this and call create_inbox.

Worked examples

Sign up for a third-party service and read the code backCall
pilotctl appstore call io.pilot.deadsimple deadsimple.get_verification_code '{"inbox_id":"<id>","since":"2026-08-06T12:00:00Z","from_contains":"stripe.com"}'
→{"data":{"found":true,"code":"481920","magic_link":null,"message_id":"..."}}

Note the time BEFORE submitting your address, pass it as `since`, then poll every 2-3s. found=false just means it has not landed yet. Never parse the raw email yourself.

Send a real emailCall
pilotctl appstore call io.pilot.deadsimple deadsimple.send_email '{"inbox_id":"<id>","to":"someone@example.com","subject":"Report ready","text_body":"The run finished."}'
→{"data":{"message_id":"...","status":"queued"}}

DKIM-signed egress, not a sandbox. Trial caps this at 10/hour, 25/day.

Read a conversation before replyingCall
pilotctl appstore call io.pilot.deadsimple deadsimple.get_thread '{"inbox_id":"<id>","thread_id":"<tid>"}'
→{"data":{"thread_id":"...","messages":[{"message_id":"...","from":"...","subject":"..."}]}}

Then reply with the message_id; threading headers are set for you.

Good to know

  • Every response is wrapped: the payload is under data, with meta.request_id beside it.
  • Call signup only when you have no key. It is idempotent per Idempotency-Key, so a retry returns the same account, not a second one.
  • Trial is 1 inbox, 10 sends/hour, 25/day. A 429 trial_send_limit_exceeded is a QUOTA signal, not transient — do not retry it.
  • Lift the caps with claim then claim_verify. Your key, inboxes and history survive.
  • get_verification_code needs since from BEFORE you triggered the mail, or you may read a stale code.

Next

  • io.pilot.deadsimple deadsimple.help '{}'

What’s New

v0.1.0Latest—
  • First release on the Pilot app store.

Platform Compatibility

macOSApple SiliconSupportedmacOSIntelSupportedLinuxarm64SupportedLinuxamd64Supported