Email

Every identity comes with a real email inbox it fully controls. Your agent can send mail from it, read what arrives, reply in-thread, and block until a verification email lands — the same inbox works over the CLI, the Python SDK, and the TypeScript SDK.

Every example below runs against one identity. Grab it once (or set it as the active identity in the CLI) and the rest follow. Need one first? See Identities.

Select the identity to work with
ravi identity use <identity-uuid>
from ravi import Ravi

ravi = Ravi(api_key="ravi_id_...")
identity = ravi.identities.get("<identity-uuid>")
import { Ravi } from "@ravi-hq/sdk";

const ravi = new Ravi({ apiKey: process.env.RAVI_API_KEY! });
const identity = await ravi.identities.get("<identity-uuid>");

Send an email

Compose and send from the identity’s address. Plain text or HTML, with optional cc, bcc, and attachments.

ravi email compose \
--to user@example.com \
--subject "Hello" \
--body "Hi from my agent"
msg = identity.email.send(
  to="user@example.com",
  subject="Hello",
  body="Hi from my agent",
)
const msg = await identity.email.send(
"user@example.com",
"Hello",
"Hi from my agent",
);

Attach files

Pass local file paths — Ravi uploads each one (up to 10 MB) and attaches it for you. Works the same on send, reply, and forward.

ravi email compose \
--to user@example.com \
--subject "Invoice" \
--body "Invoice attached." \
--attach ./invoice.pdf
msg = identity.email.send(
  to="user@example.com",
  subject="Invoice",
  body="Invoice attached.",
  attachments=["./invoice.pdf"],
)
const msg = await identity.email.send(
"user@example.com",
"Invoice",
"Invoice attached.",
{ attachments: ["./invoice.pdf"] },
);

Read the inbox

List messages as a flat feed — filter to unread to see only what needs attention.

ravi message email --unread
inbox = identity.email.inbox(unread=True)
for msg in inbox:
  print(msg.subject, msg.from_email)
const inbox = await identity.email.inbox({ unread: true });
for (const msg of inbox) {
console.log(msg.subject, msg.from_email);
}

Prefer conversations grouped by subject? List threads instead.

ravi inbox email
threads = identity.email.threads()
const threads = await identity.email.threads();

Read one message

Fetch a single message by id to see its full body and metadata.

ravi message email <message-id>
msg = identity.email.get("<message-id>")
print(msg.subject)
print(msg.body)
const msg = await identity.email.get("<message-id>");
console.log(msg.subject);
console.log(msg.body);

Reply and forward

Messages carry their own actions — reply to the sender, reply to everyone, or forward. Threading is handled for you.

Reply to the sender
ravi email reply <message-id> --body "Thanks — got it!"
msg = identity.email.get("<message-id>")
msg.reply(body="Thanks — got it!")
const msg = await identity.email.get("<message-id>");
await msg.reply("Thanks — got it!");
Reply to everyone
ravi email reply-all <message-id> --body "Thanks, all!"
msg.reply_all(body="Thanks, all!")
await msg.replyAll("Thanks, all!");
Forward
ravi email forward <message-id> --to ops@acme.com --body "FYI"
msg.forward(to="ops@acme.com")
await msg.forward("ops@acme.com");

Wait for a verification email

The move that makes agents work: trigger a signup somewhere, then block until the confirmation email arrives. wait_for polls the inbox and returns the first message that matches.

# Kick off a signup elsewhere, then wait for the email to land.
msg = identity.email.wait_for(
  lambda m: "verify" in m.subject.lower(),
  timeout=120,
)
print(msg.body)
// Kick off a signup elsewhere, then wait for the email to land.
const msg = await identity.email.waitFor(
(m) => m.subject.toLowerCase().includes("verify"),
{ timeoutMs: 120_000 },
);
console.log(msg.body);

Mark as read

msg = identity.email.get("<message-id>")
msg.mark_read()
const msg = await identity.email.get("<message-id>");
await msg.markRead();

Looking for exact request and response fields? See the full API reference.