CarlyEmail docs

SDKs

Typed clients for TypeScript and Python.

Install

npm

npm install carlyemail

pip

pip install carlyemail

Every endpoint, in both languages.

A first inbox

TypeScript

import { CarlyEmail } from "carlyemail";

const carly = new CarlyEmail();          // reads CARLYEMAIL_API_KEY

const inbox = await carly.inboxes.create({ username: "hello" });

await carly.messages.send(inbox.email, {
  to: ["you@example.com"],
  subject: "Hello",
  text: "From an agent.",
});

Python

from carlyemail import CarlyEmail

carly = CarlyEmail()                     # reads CARLYEMAIL_API_KEY

inbox = carly.inboxes.create({"username": "hello"})

carly.messages.send(
    inbox["email"],
    {"to": ["you@example.com"], "subject": "Hello", "text": "From an agent."},
)

Resources on the client: agent, auth, billing, inboxes, messages, threads, drafts, lists, domains, apiKeys / api_keys, metrics, pods, organizations, inboxEvents / inbox_events, webhooks.

Reading and replying

TypeScript

const { messages } = await carly.messages.list(inbox.email, { limit: 10 });

for (const message of messages) {
  // `extracted_text` is the new content with the quoted chain stripped, which
  // is what you want to hand a model. `text` is the whole thing.
  const body = message.extracted_text ?? message.text ?? "";
  await carly.messages.reply(inbox.email, message.message_id, {
    text: answer(body),
  });
}

Python

for message in carly.messages.list(inbox["email"], limit=10)["messages"]:
    body = message.get("extracted_text") or message.get("text") or ""
    carly.messages.reply(
        inbox["email"], message["message_id"], {"text": answer(body)}
    )

Reply to a message rather than composing a new one and it lands in the sender's existing thread — In-Reply-To and References are set for you.

Errors

Errors carry the message, the thing that clears it, and a documentation link.

TypeScript

import { CarlyEmailError } from "carlyemail";

try {
  await carly.inboxes.create({ username: "hello" });
} catch (error) {
  if (error instanceof CarlyEmailError) {
    console.log(error.status, error.code);  // 429 inbox_limit_reached
    console.log(error.fix);                 // Upgrade the plan, or delete…
    console.log(error.docs);
  }
}

Python

from carlyemail import CarlyEmailError

try:
    carly.inboxes.create({"username": "hello"})
except CarlyEmailError as error:
    print(error.status, error.code)   # 429 inbox_limit_reached
    print(error.fix)                  # Upgrade the plan, or delete…
    print(error.docs)

See errors for every code.

Configuration

The key comes from CARLYEMAIL_API_KEY unless you pass one.

TypeScript

new CarlyEmail({
  apiKey: process.env.MY_KEY,
  baseUrl: "http://localhost:8000",   // pointing at a local API
  fetch: myFetch,                     // a proxy, or retries
});

Python

CarlyEmail(
    api_key=os.environ["MY_KEY"],
    base_url="http://localhost:8000",
    timeout=60.0,
)

TypeScript has no dependencies and runs in Node, the browser, a worker and on the edge. Python needs httpx.

The CLI comes with it

npm install carlyemail also puts the CLI on your path.

npx carlyemail signup

Another language

Generate a client from the published spec.

npx @hey-api/openapi-ts -i https://docs.carlyemail.com/openapi.json -o ./carlyemail
openapi-generator-cli generate -i https://docs.carlyemail.com/openapi.json -g go -o ./carlyemail