Quickstart
Send and receive your first emails in five minutes. No DNS work required.
1. Sign up
Create an account at primitive.dev. At signup, your org is auto-issued a managed subdomain like brave-otter.primitive.email. MX and outbound records (DKIM/SPF/DMARC/TLS-RPT) are auto-published, so inbound and outbound work immediately.
Mail from *.primitive.email looks like it's from Primitive. For mail from your brand, add a custom domain. The rest of this quickstart uses the managed subdomain so there's no waiting on DNS.
2. Get an API key and webhook secret
Under Settings → API keys, click Generate. The key starts with prim_. Copy it once and store it as PRIMITIVE_API_KEY.
For inbound webhooks, also grab the signing secret from Settings → Webhooks and store it as PRIMITIVE_WEBHOOK_SECRET. The onboarding flow surfaces both on the same step if you're still in it.
3. Send your first email
From the terminal, with wait: true Primitive holds the connection until the receiver responds with an SMTP code:
curl -X POST https://primitive.dev/api/v1/send-mail \-H "Authorization: Bearer $PRIMITIVE_API_KEY" \-H "Content-Type: application/json" \-d '{"from": "hello@<your-managed>.primitive.email","to": "[email protected]","subject": "Hello from Primitive","body_text": "It works.","wait": true}'
4. Receive an email via webhook
In the dashboard, set a Webhook URL on your org. Every inbound email POSTs to this URL as signed JSON. Then pick your SDK and drop in this handler:
npm install @primitivedotdev/sdk expressExpress webhook handler.
const express = require('express');const { handleWebhook, PrimitiveWebhookError } = require('@primitivedotdev/sdk');const app = express();app.use(express.raw({ type: 'application/json' }));app.post('/webhooks/email', (req, res) => {try {const event = handleWebhook({body: req.body,headers: req.headers,secret: process.env.PRIMITIVE_WEBHOOK_SECRET,});console.log('Event:', event.id);console.log('Email from:', event.email.headers.from);console.log('Subject:', event.email.headers.subject);res.status(200).json({ received: true });} catch (error) {if (error instanceof PrimitiveWebhookError) {console.error(`[${error.code}] ${error.message}`);return res.status(400).json({ error: error.code });}throw error;}});app.listen(3000);
handleWebhook already verifies the signature, parses the JSON body, and validates email.received for you.
Send a test email to any address at your managed subdomain (e.g. [email protected]) and your handler will fire within seconds.
5. Reply to it
Inside whichever webhook handler you chose above, pass the parsed inbound email to the SDK reply helper. Node.js and Python use client.reply; Go uses client.Reply. Primitive derives the recipient, the Re: subject, and In-Reply-To / References threading headers from the parent message.
The SDKs page has the per-language reply and forward examples; Sending mail covers the reply options and failure cases.