useSendEverJust

Onboard a Product

The repeatable flow for giving a new EverJust product its own useSend tenant, sending domain, and API key.

Every EverJust product gets its own Team (tenant) inside the single useSend deployment at mail.everjust.app. A Team owns its own sending domains, contacts, campaigns, and API keys — nothing is shared between products. This page is the checklist you follow each time you stand up a new product.

Reference implementation: the Team EverJust with sending domain send.everjust.app was created with exactly these steps. Its DKIM, SPF, DMARC, and MAIL FROM records are all verified, and it has a live us_ API key. Mirror it for the next product.

Before you start

  • Access to the useSend dashboard at mail.everjust.app.
  • Ability to publish DNS records for the product's domain (Route 53 or wherever it is hosted).
  • The AWS SES region for this deployment: us-east-1. Domains must be created in this region.

Self-hosted useSend has no Route 53 (or any DNS) permission. It only shows you the records to publish — it never writes them. You add every DNS record yourself. If the domain lives in Route 53, use the repo helper scripts/add-tenant-dns.sh (in github.com/EVERJUST-DEV/usesend-email) to script it; otherwise add them by hand in your DNS provider.

The flow

Create a Team for the product

In the dashboard, create a new Team — one Team per product. The Team is the tenant boundary: its domains, API keys, contacts, campaigns, and analytics are fully isolated from every other product. Name it after the product so it is unambiguous in the Team switcher.

Team creation is a dashboard action; there is no public REST endpoint for it.

Add a sending domain

Use a subdomain dedicated to sending — e.g. send.yourproduct.com — never the product's root domain. This keeps the sending reputation and DNS isolated from the rest of the product's mail and web records.

Add it in the dashboard (Domains → Add) or over the API:

curl -X POST https://mail.everjust.app/api/v1/domains \
  -H "Authorization: Bearer us_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "send.yourproduct.com",
    "region": "us-east-1"
  }'
import { UseSend } from "usesend-js";

const usesend = new UseSend("us_xxx", "https://mail.everjust.app/api/v1");

const { data, error } = await usesend.domains.create({
  name: "send.yourproduct.com",
  region: "us-east-1",
});
from usesend import UseSend

usesend = UseSend("us_xxx", "https://mail.everjust.app/api/v1")

domain = usesend.domains.create({
    "name": "send.yourproduct.com",
    "region": "us-east-1",
})

region is required and must match the deployment's SES region (us-east-1). The response is a Domain object whose numeric id you use in later calls, and whose dnsRecords array holds the records to publish in the next step.

Publish the DNS records useSend shows you

Open the domain in the dashboard (or read dnsRecords from the create response) and publish every record. For send.yourproduct.com you get:

PurposeTypeNameValue
DKIMTXTusesend._domainkey.send.yourproduct.comthe public key useSend generated
MAIL FROMMXmail.send.yourproduct.comfeedback-smtp.us-east-1.amazonses.com (priority 10)
SPF (MAIL FROM)TXTmail.send.yourproduct.comv=spf1 include:amazonses.com ~all
DMARC (recommended)TXT_dmarc.send.yourproduct.comv=DMARC1; p=none;

Use the exact name, value, ttl, and priority values that useSend renders — the table above shows the shape, not verbatim strings. DMARC is marked recommended; publish it.

If the domain is in Route 53, script the whole set:

./scripts/add-tenant-dns.sh send.yourproduct.com

Verify the domain

Once DNS has propagated, trigger verification from the dashboard (Verify domain) or over the API:

curl -X PUT https://mail.everjust.app/api/v1/domains/42/verify \
  -H "Authorization: Bearer us_xxx"
await usesend.domains.verify(42);
usesend.domains.verify(42)

Poll the domain until its status reaches SUCCESS and dkimStatus confirms DKIM is verified — DKIM must reach SUCCESS before SES will accept sends. Propagation can take anywhere from minutes to a few hours depending on the DNS provider's TTL.

curl https://mail.everjust.app/api/v1/domains/42 \
  -H "Authorization: Bearer us_xxx"

Create a scoped API key

In Developer settings, create an API key for this product's Team. Keys carry the us_ prefix and are used as an HTTP Bearer token:

Authorization: Bearer us_xxx

Store it in the product's secret manager. API-key creation is dashboard-only — there is no public endpoint for minting keys.

Send a test to the SES simulator

SES for this deployment is currently in sandbox. Until AWS grants production access (requested, pending), you can only send to verified addresses or the SES mailbox simulator (success@simulator.amazonses.com, bounce@simulator.amazonses.com, complaint@simulator.amazonses.com). After production access is granted, you can send to any recipient.

Confirm the whole path end-to-end by sending to the simulator's success address:

curl -X POST https://mail.everjust.app/api/v1/emails \
  -H "Authorization: Bearer us_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "YourProduct <hello@send.yourproduct.com>",
    "to": "success@simulator.amazonses.com",
    "subject": "useSend onboarding test",
    "html": "<p>If this is delivered, the tenant is live.</p>"
  }'
const { data, error } = await usesend.emails.send({
  from: "YourProduct <hello@send.yourproduct.com>",
  to: "success@simulator.amazonses.com",
  subject: "useSend onboarding test",
  html: "<p>If this is delivered, the tenant is live.</p>",
});
result = usesend.emails.send({
    "from_": "YourProduct <hello@send.yourproduct.com>",
    "to": "success@simulator.amazonses.com",
    "subject": "useSend onboarding test",
    "html": "<p>If this is delivered, the tenant is live.</p>",
})

A 200 with {"emailId":"..."} means the send was accepted. Look the email up in the dashboard (or GET /v1/emails/{emailId}) and confirm its status progresses to DELIVERED.

Rate limiting is disabled on self-hosted useSend, so no throttle applies to onboarding sends or the API key you just created.

Next steps