Faivelo
Dashboard
AI & Developers

Quickstart: send and receive email from code

Send your first email, give an agent its own mailbox and read the replies. Every snippet runs as pasted.

This page gets a script or an AI agent from nothing to sending and receiving real email on your own domain. Every command runs as pasted once two values are set.

What you need first

  1. A Faivelo account with a verified domain. A person sets this up once: sign up at faivelo.com, add a domain, and Faivelo writes the DNS records for most hosts (or run npx faivelo init yourdomain.com from a terminal). See Set up from the terminal.
  2. An API key. A person on the account creates it in Settings → Developers. Pick the agent kind for anything autonomous. Give it the scopes mail:send, mail:read, mailboxes:read and mailboxes:write. The key starts with fvl_live_ and is shown once.

The API is included on every paid plan and during the free trial.

Set both values in your shell:

export FAIVELO_API_KEY="fvl_live_..."    # the key from Settings → Developers
export DOMAIN="yourdomain.com"           # a verified domain on the account

Check the key works:

curl https://faivelo.com/api/v1/mailboxes \
  -H "Authorization: Bearer $FAIVELO_API_KEY"

A 200 with {"success":true,"data":[...]} means you are ready. Anything else returns an error with a code and a fix; see Errors.

Send an email

POST /api/v1/emails sends from any address on a verified domain. No mailbox has to exist for the sender.

curl https://faivelo.com/api/v1/emails \
  -H "Authorization: Bearer $FAIVELO_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"from\": \"hello@$DOMAIN\",
    \"to\": \"you@example.com\",
    \"subject\": \"It works\",
    \"text\": \"Sent with the Faivelo API.\"
  }"

The response holds an id. GET /api/v1/emails/{id} returns its delivery status (sent, delivered, bounced, complained or failed).

To retry safely after a network error, add an Idempotency-Key header. Two requests with the same key send at most one email. See Sending via the API.

The same in Node.js

npm install faivelo
import { Faivelo } from 'faivelo'

const faivelo = new Faivelo(process.env.FAIVELO_API_KEY!)

const email = await faivelo.emails.send({
  from: `hello@${process.env.DOMAIN}`,
  to: 'you@example.com',
  subject: 'It works',
  text: 'Sent with the Faivelo SDK.'
})

console.log(email.id)

A failed call throws FaiveloError with the HTTP statusCode and the API's message.

Give an agent its own mailbox

An agent that signs up for services or talks to people needs an address that can receive mail too. Create one:

curl https://faivelo.com/api/v1/mailboxes \
  -H "Authorization: Bearer $FAIVELO_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"domain\": \"$DOMAIN\", \"localPart\": \"agent\"}"

agent@yourdomain.com now exists. An agent key can only see mailboxes it created or was granted, so it can never read the rest of the account. A key may create 10 mailboxes per 24 hours.

Send as that mailbox (the message lands in its Sent folder, and replies come back to it):

curl "https://faivelo.com/api/v1/mailboxes/agent@$DOMAIN/send" \
  -H "Authorization: Bearer $FAIVELO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to": "you@example.com", "subject": "Hello from an agent", "text": "Reply to this and I will read it."}'

Read the replies

List the newest messages in the inbox:

curl "https://faivelo.com/api/v1/mailboxes/agent@$DOMAIN/messages?folder=INBOX&limit=10" \
  -H "Authorization: Bearer $FAIVELO_API_KEY"

Each message has a uid. Read one in full, body included:

curl "https://faivelo.com/api/v1/mailboxes/agent@$DOMAIN/messages/<uid>" \
  -H "Authorization: Bearer $FAIVELO_API_KEY"

Polling works for a script that waits for one verification code. For anything long-running, use a webhook instead.

Get replies pushed as webhooks

Add an endpoint in Settings → Developers → Webhooks and subscribe to message.received (Pro and Business). Faivelo sends a signed POST to your URL the moment mail arrives:

{
  "id": "evt_01J8ZK3V5QXR7",
  "type": "message.received",
  "created_at": "2026-09-20T14:02:11Z",
  "data": {
    "mailbox": "agent@yourdomain.com",
    "message_id": "eaaaaab",
    "thread_id": "b",
    "folder": "INBOX",
    "from": { "name": "Dana Whitfield", "address": "dana@northwind.io" },
    "subject": "Re: Hello from an agent",
    "snippet": "Thanks, here is the code you asked for..."
  }
}

Check the signature before trusting the body. Pass the raw body, not parsed JSON:

import { Faivelo } from 'faivelo'

const event = await Faivelo.webhooks.verify(
  rawBody,
  request.headers['x-faivelo-signature'],
  process.env.FAIVELO_WEBHOOK_SECRET!
)

if (event.type === 'message.received') {
  // event.data.message_id works anywhere the API takes a message uid
}

Every event, the payloads and the retry rules are in Webhooks.

Use it from an AI agent over MCP

The hosted MCP server exposes the same actions as tools (send_message, list_messages, read_message, create_mailbox and more) at https://faivelo.com/api/mcp, over Streamable HTTP. It is included from the Growth plan.

Claude Code, with an API key:

claude mcp add --transport http faivelo https://faivelo.com/api/mcp \
  --header "Authorization: Bearer $FAIVELO_API_KEY"

Any MCP client that reads JSON config:

{
  "mcpServers": {
    "faivelo": {
      "type": "http",
      "url": "https://faivelo.com/api/mcp",
      "headers": { "Authorization": "Bearer fvl_live_..." }
    }
  }
}

Without a key, claude mcp add --transport http faivelo https://faivelo.com/api/mcp signs in through the browser instead, and the person picks which mailboxes the agent may use. See Connect Claude and AI agents & API keys.

For agents reading this page