Skip to content

Email

Available

The Email service sends transactional email — sign-up confirmations, password resets, receipts, alerts — through a simple REST API. Authenticate with an API key, send a JSON payload, and track delivery in real time.

Email serviceA logical sender, scoped to a workspace. You can have several services per workspace (for example one per app or per environment).
Sending domainA domain you own that has been verified for sending email.
API keyThe credential used to authenticate API requests.
Sandbox modeA safe mode for testing that only delivers to verified recipients.
POST /api/email/services
Content-Type: application/json
{
"name": "production-app"
}

Each service starts in sandbox mode. To send to any recipient, switch the service to production mode after verifying at least one sending domain.

Add and verify the domain you want to send from.

POST /api/email/services/{service_id}/domains
Content-Type: application/json
{
"domain": "mail.example.com"
}

The response includes the DNS records you need to add at your registrar:

RecordPurpose
SPF (TXT)Authorizes Runsite to send on behalf of your domain.
DKIM (TXT, two keys)Cryptographically signs outgoing messages so recipients can verify authenticity.
DMARC (TXT, optional but recommended)Tells receivers how to handle messages that fail SPF/DKIM.
MX (optional)Required only if you want to receive bounces back through Runsite.

After the records propagate, trigger verification:

POST /api/email/services/{service_id}/domains/{domain_id}/verify

Once a domain is verified, you can send From: any address at that domain.

While the service is in sandbox mode, only verified recipient addresses receive email. Other addresses are silently dropped (and logged as dropped: sandbox). Use this for early development.

Verify a sandbox recipient:

POST /api/email/services/{service_id}/sandbox-emails
Content-Type: application/json
{
"email": "you@example.com"
}

The recipient receives a verification link they must click before they can be used.

POST /api/email/services/{service_id}/api-keys
Content-Type: application/json
{
"name": "production-server"
}

The secret is returned once. Store it in your application’s environment, not in source.

POST /api/email/services/{service_id}/send
Authorization: Bearer rsk_email_...
Content-Type: application/json
{
"from": "Acme <hello@mail.example.com>",
"to": ["user@gmail.com"],
"subject": "Welcome to Acme",
"html": "<p>Thanks for signing up!</p>",
"text": "Thanks for signing up!"
}

Optional fields:

FieldDescription
cc, bccStandard recipient lists.
reply_toOverride the Reply-To: header.
headersCustom headers as a JSON object.
attachmentsArray of { filename, content_base64, content_type }.
tagsArray of strings for filtering stats and webhooks.
const res = await fetch(
`https://api.runsite.app/api/email/services/${serviceId}/send`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.RUNSITE_EMAIL_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
from: 'Acme <hello@mail.example.com>',
to: ['user@gmail.com'],
subject: 'Welcome to Acme',
html: '<p>Thanks for signing up!</p>',
}),
},
);
import os, requests
requests.post(
f"https://api.runsite.app/api/email/services/{service_id}/send",
headers={"Authorization": f"Bearer {os.environ['RUNSITE_EMAIL_KEY']}"},
json={
"from": "Acme <hello@mail.example.com>",
"to": ["user@gmail.com"],
"subject": "Welcome to Acme",
"html": "<p>Thanks for signing up!</p>",
},
)

Subscribe to delivery events to react in your application — for example, mark a recipient as bounced or count complaints.

POST /api/email/services/{service_id}/webhooks
Content-Type: application/json
{
"url": "https://example.com/webhooks/email",
"events": ["delivered", "bounced", "complained", "opened", "clicked"]
}

Every event is signed; verify the signature header before trusting the payload.

EventWhen it fires
sentRunsite has accepted the message and queued it for delivery.
deliveredThe receiving server accepted the message.
bouncedThe receiving server rejected the message (hard or soft bounce).
complainedThe recipient marked the message as spam.
openedThe recipient opened the email (when tracking pixels are enabled).
clickedThe recipient clicked a tracked link.
GET /api/email/services/{service_id}/stats?period=7d

Returns counts for sent, delivered, bounced, complained, and dropped messages, optionally bucketed by day or hour.

Each service has a per-minute and per-day send rate. Limits are visible on the service detail page and increase automatically with sending reputation.

Suppression list

Recipients that hard-bounce or mark messages as spam are added to a per-service suppression list automatically. You can view and manage the list from the dashboard or API.