Quickstart
This path gets a new account from zero to sending, receiving, and replying without touching DNS. It uses the managed *.primitive.email subdomain and the primitive CLI.
1. Create an Account
Sign up at primitive.dev. Your organization receives a managed subdomain like brave-otter.primitive.email.
The managed subdomain has MX and outbound records published automatically. You can receive inbound mail and send from addresses on that subdomain immediately.
2. Install And Login With The CLI
The CLI uses OAuth, so you do not need to create or paste an API key for terminal use.
brew install primitivedotdev/tap/primitive # or: npm install -g @primitivedotdev/cli primitive login primitive whoami
If you cannot install globally, run commands with npx @primitivedotdev/cli@latest.
Homebrew installs the required Node.js runtime automatically; npm and npx require Node.js 22 or newer. The CLI package and runtime SDK are separate: use @primitivedotdev/cli for the primitive binary, and use @primitivedotdev/sdk inside application code.
3. Create Optional cURL Credentials
If you use the cURL examples in this guide, open Settings -> API keys and create an API key. Store it as PRIMITIVE_API_KEY. CLI-only users can skip this.
For webhook verification, open Settings -> Webhooks and copy the signing secret as PRIMITIVE_WEBHOOK_SECRET.
export PRIMITIVE_API_KEY=prim_... export PRIMITIVE_WEBHOOK_SECRET=whsec_...
4. Verify API Access
primitive whoami5. Scaffold a Function
Functions are the fastest receive path because Primitive hosts the handler and wires it to inbound mail.
primitive functions:init my-fn cd my-fn npm install npm run build
This step is local project generation. There is no REST endpoint for scaffolding files on your machine; use REST/curl at deploy time.
The scaffold contains handler.ts, build.mjs, package.json, tsconfig.json, and a README. It imports the runtime client correctly and uses the bundler settings expected by Primitive Functions.
6. Deploy the Function
Deploy creates the Function and auto-registers an inbound endpoint for the organization. Save the returned Function id for later redeploys.
7. Send an Email
Use the CLI first because it auto-resolves a usable from address on your managed domain.
The --wait flag blocks until Primitive has a delivery result from the receiving side.
8. Understand First-Send Gates
New accounts can send to:
- addresses on
*.primitive.email; - addresses on domains you have verified;
- email addresses that belong to members of your Primitive organization;
- external addresses that have already sent you authenticated mail, when replying to known addresses is allowed;
- any domain only after support enables broader outbound sending for your organization.
If a first send to Gmail, Outlook, Fastmail, or another external address returns 403 recipient_not_allowed, inspect the returned gates and fix.action fields. See Sending Mail for the full model.
9. Receive an Email
Send a test message to any address at your managed subdomain, for example hi@your-org.primitive.email.
Primitive receives it through MX, parses it, stores it, signs the event, and invokes your Function. You can also read it from the CLI:
primitive emails:latest --limit 5 primitive emails:get-email --id <email-id>
10. Reply
Reply to an inbound message with threading derived from the original email:
In SDK code, use client.reply(email, ...) in Node.js or Python and client.Reply(...) in Go. Primitive derives the recipient, Re: subject, In-Reply-To, and References headers.
Go Deeper
- Functions: handler shape, deploys, tests, logs, secrets, and limits.
- Sending Mail: sends, replies, forwards, idempotency, and gates.
- Receiving Mail: webhooks, retries, replays, and storage.
- SDKs: Node.js, Python, and Go examples.