Skip to main content

Sending Emails

Relay provides three endpoints for sending emails: single send, template send, and batch send. All require an API key with the send scope.

Authentication

Include your API key in the X-Relay-Key header:

X-Relay-Key: relay_key_abc123...

Single Send

POST /api/send — Send one email to one or more recipients.

Request

{
"from": "[email protected]",
"to": ["[email protected]"],
"subject": "Ticket #1234 Updated",
"html": "<h1>Ticket Updated</h1><p>Your ticket has been assigned.</p>",
"text": "Ticket Updated\nYour ticket has been assigned.",
"reply_to": "[email protected]",
"cc": ["[email protected]"],
"bcc": ["[email protected]"],
"tags": {
"product": "psa",
"ticket_id": "1234"
},
"attachments": [
{
"filename": "report.pdf",
"content": "base64-encoded-content",
"content_type": "application/pdf"
}
]
}

Fields

FieldRequiredDescription
fromYesSender address. Must be on a verified domain.
toYesArray of recipient email addresses
subjectYesEmail subject line
htmlYes*HTML body (*at least one of html or text required)
textNoPlain text fallback body
reply_toNoReply-to address
ccNoArray of CC addresses
bccNoArray of BCC addresses
tagsNoKey-value metadata for tracking and analytics
attachmentsNoArray of attachments (max 10, base64-encoded)

Response

{
"message_id": "msg_abc123...",
"status": "sent",
"ses_message_id": "0100018e..."
}

Validation

Before sending, Relay checks:

  1. Domain verified — The from address domain must be verified in your account
  2. Suppressions — All to, cc, and bcc addresses are checked against the suppression list. Suppressed addresses are skipped.
  3. Rate limits — Your tenant's rate limits are checked across all four windows

If the domain is not verified, the request returns 400. If all recipients are suppressed, it returns 400. If rate limited, it returns 429 with a Retry-After header.

Template Send

POST /api/send-template — Send using a saved template with variable substitution.

Request

{
"from": "[email protected]",
"to": ["[email protected]"],
"template_id": "tmpl_welcome_123",
"variables": {
"client_name": "Acme Corp",
"technician": "Sarah",
"ticket_url": "https://portal.yourmsp.com/tickets/1234"
},
"reply_to": "[email protected]",
"tags": {
"product": "portal",
"type": "welcome"
}
}
FieldRequiredDescription
fromYesSender address on a verified domain
toYesArray of recipient addresses
template_idYesID of a saved template
variablesNoKey-value pairs replacing {{variable}} placeholders in the template
reply_toNoReply-to address
tagsNoTracking metadata

The template's subject, HTML, and text fields all support {{variable}} substitution. Any unreplaced variables remain as-is in the output.

Batch Send

POST /api/send-batch — Send up to 50 emails in a single API call.

Requires both send and send-batch scopes on your API key.

Request

{
"emails": [
{
"from": "[email protected]",
"to": ["[email protected]"],
"subject": "Invoice Ready",
"html": "<p>Your invoice is ready.</p>"
},
{
"from": "[email protected]",
"to": ["[email protected]"],
"subject": "Invoice Ready",
"html": "<p>Your invoice is ready.</p>"
}
]
}

Each item in the emails array follows the same format as a single send request.

Response

{
"results": [
{ "message_id": "msg_abc...", "status": "sent", "ses_message_id": "010001..." },
{ "message_id": "msg_def...", "status": "sent", "ses_message_id": "010002..." }
],
"total": 2,
"sent": 2,
"failed": 0
}

Each email is validated independently. If one email fails (bad recipient, suppressed, etc.), the others still send. The response includes per-message results.

ℹ️Batch sends process up to 10 emails concurrently. A batch of 50 emails completes in roughly 5 sequential rounds. Plan accordingly for time-sensitive sends.

Limits

  • Maximum 50 emails per batch request
  • Each email counts individually against rate limits
  • Batch requests that exceed 50 emails return 400

Error Responses

StatusMeaning
200Email sent successfully
400Validation error — unverified domain, missing fields, all recipients suppressed, batch too large
401Missing or invalid API key
403API key lacks required scope
429Rate limit exceeded — check Retry-After header
500Internal error — retry with exponential backoff

Tags and Tracking

Tags are key-value pairs attached to each email. They flow through the entire lifecycle (send → delivery → bounce → analytics) and enable filtering in logs and segmentation in analytics.

Common tag patterns:

{
"product": "psa",
"type": "ticket_notification",
"org_id": "org_123",
"ticket_id": "1234"
}

Tags appear in email logs and the analytics "By Product" breakdown.

SDK Usage

The TypeScript SDK wraps all three endpoints:

import { RelayClient } from '@theonefamily/relay-sdk';

const relay = new RelayClient({
apiKey: process.env.RELAY_API_KEY,
});

// Single send
await relay.send({ from, to, subject, html });

// Template send
await relay.sendTemplate({ from, to, template_id, variables });

// Batch send
await relay.sendBatch({ emails: [{ from, to, subject, html }, ...] });